Codeforces Round #662 (Div. 2)
阿新 • • 發佈:2020-08-08
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; returnView Code1; } 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\n",ans); } }
D
b[i][j]表示從i,j格開始向左右兩邊擴充套件(相同字元可以擴充套件)的最大的長度,c[i][j]表示從i,j格開始向上下兩邊擴充套件(相同字元可以擴充套件)的最大的長度。然後掃描每一個格子時用線段樹,細節有點多,看我程式碼應該能完全懂,複雜度O(nmlogn)
#include<bits/stdc++.h> #defineView Codelson 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 上橙啦