版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/83933795
二维树状数组裸题,没啥好说的,水题。
#include<cstdio>
#define low(x) x&-x
using namespace std;
const int maxn=1005;
int c[26][maxn][maxn],n,m;
char s[maxn][maxn],str[2];
void up(int i,int p,int q,int v)
{
for(int j=p;j<=n;j+=low(j))
for(int k=q;k<=m;k+=low(k))
c[i][j][k]+=v;
}
int qu(int i,int p,int q)
{
int res=0;
for(int j=p;j;j-=low(j))
for(int k=q;k;k-=low(k))
res+=c[i][j][k];
return res;
}
int main()
{
int q;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<26;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++)c[i][j][k]=0;
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
for(int j=1;j<=m;j++)
up(s[i][j]-'a',i,j,1);
}
scanf("%d",&q);
while(q--)
{
int op,x1,y1,x2,y2;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=0;i<26;i++)
{
int t=qu(i,x2,y2)+qu(i,x1-1,y1-1);
t-=qu(i,x1-1,y2)+qu(i,x2,y1-1);
printf("%d%c",t,i==25?'\n':' ');
}
}
else
{
scanf("%d%d%s",&x1,&y1,str);
up(s[x1][y1]-'a',x1,y1,-1);
s[x1][y1]=str[0];
up(s[x1][y1]-'a',x1,y1,1);
}
}
}
}
设f[x]为01串下标1到x中1的个数(我的下标从1开始),d[x]为01串下标1到x中0的个数,假设我翻转了 l r区间,那么ans=f[n]-f[r]+f[l-1]+d[r]-d[l-1],f[n]是常数,我们变形一下,答案值和这个有关:f[l-1]-d[l-1]-(f[r]-d[r]),那么只要这个式子最大,答案才最大,我们令h[x]=f[x]-d[x],只要找到两个数 l r(l<=r),使得h[l]-h[r]最大即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
char s[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d%s",&n,s+1);
int ans=0,p0=0,p1=0,mx=0,p=0;
for(int i=1;i<=n;i++)
{
ans+=s[i]-'0';
if(s[i]=='0')p0++;
else p1++;
int t=p1-p0;
p=max(p,mx-t);
mx=max(t,mx);
}
printf("%d\n",ans+p);
}
}
水题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=3e5+10;
int vis[maxn],a[maxn],vis2[maxn];
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
int mx=0,x;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
vis[x]++;
mx=max(mx,vis[x]);
}
for(int i=1;i<=30000;i++)
if(vis[i]==mx)
printf("%d %d\n",i,mx);
}
}
这个题有点巧妙,求一个最短的01串的长度,该串不是题目给的串的子串,因为题目的串最长只有1e5,所以答案最大也是log2(1e5),大概是17的样子吧,因为长度为17的不同的01串数量超过了1e5,所以我只要从标准串的所有长度不超过17的子串换成数字标记即可,最后从0开始枚举,如果某个数字每被标记,那么这个数字换成的01串的长度就是答案。
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e5+10;
char s[maxn];
int vis[maxn*10];
int main()
{
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;i++)
{
int t=0;
for(int j=i;j<=i+18&&j<=n;j++)
{
t=t*2+s[j]-'0';
vis[t]++;
}
}
for(int i=0;;i++)
{
if(!vis[i])
{
if(i==0)
{
puts("1");
return 0;
}
int t=log2(i);
printf("%d\n",t+1);
return 0;
}
}
}
这个模拟题表示没看懂啊,n=2有示范,n=3呢......
//打cf去了