AB
签到
C
开始还写个假的模拟法,后来发现可以直接贪心,从大到小枚举答案x,发现相同数的个数不超过n/x+1,且等于n/x+1的不超过n%x即可
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m,ans,a[N],b[N],c[N]; bool check(int x) { int num=n/x,mx=n%x; if(a[1]>num+1)return 0; if(m>mx&&a[mx+1]>num)return 0; return 1; } int main() { int T;scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n+1;i++)a[i]=b[i]=c[i]=0; for(int i=1,x;i<=n;i++)scanf("%d",&x),b[x]++; m=ans=0; for(int i=1;i<=n;i++)if(b[i])a[++m]=b[i]; sort(a+1,a+m+1),reverse(a+1,a+m+1); for(int i=n-1;~i;i--) if(check(i+1)){ans=i;break;} printf("%d ",ans); } }
D
b[i][j]表示从i,j格开始向左右两边扩展(相同字符可以扩展)的最大的长度,c[i][j]表示从i,j格开始向上下两边扩展(相同字符可以扩展)的最大的长度。然后扫描每一个格子时用线段树,细节有点多,看我代码应该能完全懂,复杂度O(nmlogn)
#include<bits/stdc++.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; typedef long long ll; const int N=2200; int n,m,d[N],mn[N<<2],lazy[N<<2],b[N][N],c[N][N]; ll ans; char a[N][N]; void sol1(int i,int l,int r){for(int j=l;j<=r;j++)b[i][j]=min(j-l,r-j);} void sol2(int j,int l,int r){for(int i=l;i<=r;i++)c[i][j]=min(i-l,r-i);} void build(int l,int r,int rt) { lazy[rt]=0; if(l==r){mn[rt]=d[l];return;} int mid=l+r>>1; build(lson),build(rson); mn[rt]=min(mn[rt<<1],mn[rt<<1|1]); } void pushdown(int rt) { int v; if(lazy[rt]) v=lazy[rt],mn[rt<<1]+=v,lazy[rt<<1]+=v,mn[rt<<1|1]+=v,lazy[rt<<1|1]+=v,lazy[rt]=0; } void update(int L,int R,int v,int l,int r,int rt) { if(L<=l&&r<=R){mn[rt]+=v,lazy[rt]+=v;return;} pushdown(rt); int mid=l+r>>1; if(L<=mid)update(L,R,v,lson); if(R>mid)update(L,R,v,rson); mn[rt]=min(mn[rt<<1],mn[rt<<1|1]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%s",a[i]+1); if(n==1||m==1){printf("%d",n*m);return 0;} for(int i=1;i<=n;i++) { int l=1,r; for(r=2;r<=m;r++)if(a[i][r]!=a[i][r-1])sol1(i,l,r-1),l=r; sol1(i,l,m); } for(int j=1;j<=m;j++) { int l=1,r; for(r=2;r<=n;r++)if(a[r][j]!=a[r-1][j])sol2(j,l,r-1),l=r; sol2(j,l,n); } for(int j=1;j<=m;j++) { for(int i=1;i<=n;i++)d[i]=b[i][j]+i-1; build(1,n,1); for(int i=1;i<=n;i++) { ans+=min(c[i][j],min(min(i-1,n-i),mn[1]))+1; if(i<n)update(1,i,1,1,n,1),update(i+1,n,-1,1,n,1); } } printf("%lld",ans); }
E
E1口胡了一个O(串长^2),感觉是后缀数组+DP,但老年选手写不来
用KD-Tree打的,rank55 rating+=104 上橙啦