期望得分:100+100+30=230

实际得分:

正解:

枚举最高的位,这一位m是1但实际用了0

然后剩余的低位肯定是 正数就用1,负数用0

考场思路:数位DP

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> using namespace std; typedef long long LL; #define N 100001 int a[N]; char s[N]; LL dp[N][]; void read(int &x)
{
x=; int f=; char c=getchar();
while(!isdigit(c)) { if(c=='-') f=-; c=getchar(); }
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
x*=f;
} LL dfs(int dep,int num,bool lim)
{
if(!dep) return ;
if(!lim && dp[dep][num]!=-) return dp[dep][num];
int up= lim ? s[dep]-'' : ; LL res=;
res=dfs(dep-,,lim && ==s[dep]-'');
if(up) res=max(res,a[dep]+dfs(dep-,,lim && ==s[dep]-''));
if(!lim) dp[dep][num]=res;
return res;
} int main()
{
freopen("maximum.in","r",stdin);
freopen("maximum.out","w",stdout);
int n;
read(n);
for(int i=;i<=n;i++) read(a[i]);
scanf("%s",s+);
memset(dp,-,sizeof(dp));
cout<<dfs(n,,);
}

二分+DP

dp[i] 表示 到第i个数, 在满足条件(任意两个相邻的数,差<=mid)的情况下,并且i没有被改变,最少改变多少数字。

状态转移: dp[i]=dp[k]+(i-k-1)    k=0~i-1  表示 k+1~i-1 都被改变了

转移条件:mid*(k-i)>=abs(a[k]-a[i])  k~i这段区间能满足条件

只管修改了多少个数,至于改成了什么,不关心

最大的差最小,就是让数均匀分布,那么二分最大的差,条件就是差*个数>= | 区间右边-左边 |

也就是假设区间左右端点都不改变,而区间内部都改变

区间内部都改变是最差的情况,他会随着区间左端点的移动而变小

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; #define N 1001 int dp[N],a[N]; int n,k; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} bool check(int mid)
{
for(int i=;i<=n;i++)
{
dp[i]=i-;
for(int j=;j<i;j++)
if(abs(a[i]-a[j])<=mid*(i-j)) dp[i]=min(dp[i],dp[j]+i-j-);
}
int mi=dp[n];
for(int i=;i<n;i++) mi=min(mi,dp[i]+n-i);
return mi<=k;
} int main()
{
freopen("minimum.in","r",stdin);
freopen("minimum.out","w",stdout);
read(n); read(k);
for(int i=;i<=n;i++) read(a[i]);
int l=,r=,mid,ans;
for(int i=;i<=n;i++) r=max(r,abs(a[i]-a[i-]));
ans=r;
while(l<=r)
{
mid=l+r>>;
if(check(mid)) ans=mid,r=mid-;
else l=mid+;
}
printf("%d",ans);
}

将A看做+y,B看做-x,问题转化为 在[L,R] 内 求 最长和为0的区间

记录 前缀和 a[i] ,若 a[v]-a[u]=0 ,则 [u+1,v] 为 一个和为0的区间

将所有的前缀和离散化为c[i]

pos[i]  表示 当前 离散化 后为i的数 第一次 出现在pos[i]

假设当前在位置j,

若 pos[c[j]] 之前被更新过了,那么 [ pos[c[j]],j ] 就是一个 和为0的区间 ,且是以j为右端点的最长的

若没有被更新,用j更新pos[c[j]]

将 字符串分为根号n 块

用上述方法在n*根号n 时间 内 预处理完 这三个数组:

two[i][j]  i,j <= 根号n ,第i个块到第j个块之间 和为0 的最长区间

l[i][j]  i <= 根号 n ,j <=n,区间[ 第i块的第一个位置,j ]  和为0的最长区间

r[i][j] i <= 根号 n ,j <=n,区间[ j+1,第i块的最后一个位置 ] 和为0的最长区间

对于 一个询问 L,R

由四部分更新

设L所在块为bL,R所在块为bR

① 最优解 在 [L,R] 完整的块内 即 two[bL+1][bR-1]

② 最优解的左端点 不在[L,R] 完整块内,右端点在[L,R]完整块内 即 r[bR-1][L-1]

③ 最优解的左端点 在[L,R]完整块内,右端点不在[L,R] 完整块内,即l[bL+1][R]

④ 最优解 的左右端点都不在[L,R] 完整块内 ,

那么 用上面的方法 枚举 左边不在完整块内的部分,枚举右边不在完整块内的部分,O(2*根号n) 求解

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> using namespace std; #define N 100001 char s[N]; int a[N],b[N],c[N]; int two[][],l[][N],r[][N]; int pos[N]; int use[N]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} int getgcd(int a,int b) { return !b ? a : getgcd(b,a%b); } int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
int n,x,y;
read(n); read(x); read(y);
int g=getgcd(x,y); x/=g; y/=g;
scanf("%s",s+);
for(int i=;i<=n;++i)
{
if(s[i]=='A') a[i]=a[i-]+y;
else a[i]=a[i-]-x;
b[i]=a[i];
}
sort(b+,b+n+);
int tot=unique(b+,b+n+)-b-;
for(int i=;i<=n;++i) c[i]=lower_bound(b+,b+tot+,a[i])-b;
int siz=sqrt(n),mx,m=siz;
int cnt=;
memset(pos,-,sizeof(pos));
for(int i=,k=;i<=n;i+=siz,++k)
{
mx=cnt=;
for(int j=i,kk=k;j<=n;j+=siz,++kk)
{
for(int h=;h<=siz;++h)
{
if(pos[c[j+h-]]!=-) mx=max(mx,j+h--pos[c[j+h-]]);
else pos[c[j+h-]]=j+h-;
use[++cnt]=c[j+h-];
}
two[k][kk]=mx;
}
for(int i=;i<=cnt;++i) pos[use[i]]=-;
}
for(int i=,k=;i<=n;i+=siz,++k)
{
cnt=;
for(int j=i;j<=n;++j)
{
if(pos[c[j]]!=-) l[k][j]=max(l[k][j-],j-pos[c[j]]);
else l[k][j]=l[k][j-],pos[c[j]]=j;
use[++cnt]=c[j];
}
for(int j=;j<=cnt;++j) pos[use[j]]=-;
}
for(int i=siz,k=;i<=n;i+=siz,++k)
{
cnt=;
for(int j=i;j>=;--j)
{
if(pos[c[j]]!=-) r[k][j]=max(r[k][j+],pos[c[j]]-j);
else r[k][j]=r[k][j+],pos[c[j]]=j;
use[++cnt]=c[j];
}
for(int j=;j<=cnt;++j) pos[use[j]]=-;
}
int q;
read(q);
int L,R; int bL,bR; int ans;
while(q--)
{
read(L); read(R);
bL=(L-)/siz+; bR=(R-)/siz+;
ans=;
if(bR-bL<)
{
cnt=;
for(int i=L-;i<=R;++i)
{
if(pos[c[i]]!=-) ans=max(ans,i-pos[c[i]]);
else pos[c[i]]=i;
use[++cnt]=c[i];
}
for(int i=;i<=cnt;++i) pos[use[i]]=-;
}
else
{
ans=two[bL+][bR-];
ans=max(ans,r[bR-][L-]);
ans=max(ans,l[bL+][R]);
cnt=;
int t=bL*siz;
for(int i=L-;i<=t;++i)
{
if(pos[c[i]]!=-) ans=max(ans,i-pos[c[i]]);
else pos[c[i]]=i;
use[++cnt]=c[i];
}
for(int i=(bR-)*siz+;i<=R;++i)
{
if(pos[c[i]]!=-) ans=max(ans,i-pos[c[i]]);
else pos[c[i]]=i;
use[++cnt]=c[i];
}
for(int i=;i<=cnt;++i) pos[use[i]]=-;
}
cout<<ans<<'\n';
}
}

2017 清北济南考前刷题Day 6 afternoon的更多相关文章

  1. 2017 清北济南考前刷题Day 7 afternoon

    期望得分:100+100+30=230 实际得分:100+100+30=230 1. 三向城 题目描述 三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口.(来自取名力为0的 ...

  2. 2017 清北济南考前刷题Day 1 afternoon

    期望得分:80+30+70=180 实际得分:10+30+70=110 T1 水题(water) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK出了道水 ...

  3. 2017 清北济南考前刷题Day 3 afternoon

    期望得分:100+40+100=240 实际得分:100+40+100=240 将每个联通块的贡献乘起来就是答案 如果一个联通块的边数>点数 ,那么无解 如果边数=点数,那么贡献是 2 如果边数 ...

  4. 2017 清北济南考前刷题Day 4 afternoon

    期望得分:30+50+30=110 实际得分:40+0+0=40 并查集合并再次写炸... 模拟更相减损术的过程 更相减损术,差一定比被减数小,当被减数=减数时,停止 对于同一个减数来说,会被减 第1 ...

  5. 2017 清北济南考前刷题Day 5 afternoon

    期望得分:100+100+30=230 实际得分:0+0+0=30 T1 直接模拟 #include<cstdio> #include<iostream> using name ...

  6. 2017 清北济南考前刷题Day 2 afternoon

    期望得分:100+60+70=230 实际得分:0+60+0=60 T1 可以证明如果一对括号原本就匹配,那么这对括号在最优解中一定不会被分开 所以用栈记录下没有匹配的括号 最后栈中一定是 一堆右括号 ...

  7. 2017 清北济南考前刷题Day 3 morning

    实际得分:100+0+0=100 T1 右上角是必败态,然后推下去 发现同行全是必胜态或全是必败态,不同行必胜必败交叉 列同行 所以n,m 只要有一个是偶数,先手必胜 #include<cstd ...

  8. 2017 清北济南考前刷题Day 7 morning

    期望得分:100+50+20=170 实际得分:10+50+20=80 1. 纸牌 题目描述 在桌面上放着n张纸牌,每张纸牌有两面,每面都写着一个非负整数.你的邪王真眼可以看到所有牌朝上的一面和朝下的 ...

  9. 2017 清北济南考前刷题Day 6 morning

    T1 贪心 10 元先找5元 20元 先找10+5,再找3张5 #include<cstdio> using namespace std; int m5,m10,m20; int main ...

随机推荐

  1. PHP 常用函数总结(三)

    7.PHP JSON 格式 json_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] ) 返回字符串,包含了 valu ...

  2. [转帖]InfiniBand 主流厂商 和 产品分析

    InfiniBand 主流厂商 和 产品分析   Mellanox成立于1999年,总部设在美国加州和以色列,Mellanox公司是服务器和存储端到端连接InfiniBand解决方案的领先供应商.20 ...

  3. 一个Flume 异常(Put queue for MemoryTransaction of capacity 100 full)的排查和解决思路

    最近在做一个分布式调用链跟踪系统, 在两个地方采用了flume (我使用的flume版本是1.5.0-cdh5.4.4),一个是宿主系统 ,用flume agent进行日志搜集. 一个是从kafka拉 ...

  4. 熟悉常用Linux操作

    cd命令:切换目录 (1)切换到目录 /usr/local cd /usr/local (2)去到目前的上层目录 cd .. (3)回到自己的主文件夹 cd ~ ls命令:查看文件与目录 (4)查看目 ...

  5. python的N个小功能(找到要爬取的验证码链接,并大量下载验证码样本)

    # -*- coding: utf-8 -*- """ Created on Mon Mar 21 11:04:54 2017 @author: sl "&qu ...

  6. 对final和static的理解

    一.final (一).final的使用 final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量) 1. 当用final修饰一个类时,表明这个类不能被继承.2. 当用final修饰一个方法 ...

  7. 51nod 1376 最长上升子序列的数量 | DP | vector怒刷存在感!

    51nod 1376 最长上升子序列的数量 题解 我们设lis[i]为以位置i结尾的最长上升子序列长度,dp[i]为以位置i结尾的最长上升子序列数量. 显然,dp[i]要从前面的一些位置(设为位置j) ...

  8. Linux系统中/opt 和 /usr目录

    重点:usr是Unix Software Resource的缩写,即“UNIX操作系统软件资源”所放置的目录. 下面是个人找到的适合类似我这种从Windows转向Linux小白的文章. Ref:htt ...

  9. 解题:Poetize6 IncDec Sequence

    题面 差分原数列得到差分数组$dif$,这样对于$dif[2]->dif[n]$会多出来两个“空位置”$1$和$n+1$.然后区间加减就变成了使一个位置$+1$,另一个位置$-1$(可以对“空位 ...

  10. 解题:JSOI 2008 Blue Mary的战略地图

    题面 这大概不算是从零开始的DP学习系列,这不是最大子矩形吗=.= 定义$dp[x][y][xx][yy]$表示第一张地图中右下角为$(x,y)$,第二张地图中右下角为$(xx,yy)$的最大公共子矩 ...