中南oj 2018年11月月賽Div1 題解
阿新 • • 發佈:2018-11-22
二維樹狀陣列裸題,沒啥好說的,水題。
#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去了