A:签到。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } ll x,y,z; signed main() { cin>>x>>y>>z; cout<<(x+y)/z<<' '; if (x%z+y%z<z) cout<<0; else cout<<min(z-x%z,z-y%z); return 0; //NOTICE LONG LONG!!!!! }
B:显然在中间截比较优。于是就找到在左侧和在右侧的最靠近中点的切割点。注意不能有前导0。高精加即可。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N],b[N],c[N],d[N],len1=N,len2=N; char s[N]; signed main() { n=read(); scanf("%s",s+1); int x=0,y=n+1; for (int i=1;i<n;i++) if (s[i+1]!='0') { if (i<=n/2) x=max(x,i); else y=min(y,i); } if (x>0) { int lena=0,lenb=0; for (int i=x;i>=1;i--) a[++lena]=s[i]-'0'; for (int i=n;i>x;i--) b[++lenb]=s[i]-'0'; for (int i=1;i<=max(lena,lenb);i++) { a[i]+=b[i]; a[i+1]+=a[i]/10; a[i]%=10; } len1=max(lena,lenb); if (a[len1+1]) len1++; } if (y<=n) { int lena=0,lenb=0; for (int i=y;i>=1;i--) c[++lena]=s[i]-'0'; for (int i=n;i>y;i--) d[++lenb]=s[i]-'0'; for (int i=1;i<=max(lena,lenb);i++) { c[i]+=d[i]; c[i+1]+=c[i]/10; c[i]%=10; } len2=max(lena,lenb); if (c[len2+1]) len2++; } if (len1<len2) { for (int i=len1;i>=1;i--) printf("%d",a[i]); } else if (len1>len2) { for (int i=len2;i>=1;i--) printf("%d",c[i]); } else { bool flag1=0; for (int i=len1;i>=1;i--) if (a[i]!=c[i]) { flag1=a[i]<c[i]; break; } if (flag1) for (int i=len1;i>=1;i--) printf("%d",a[i]); else for (int i=len2;i>=1;i--) printf("%d",c[i]); } return 0; //NOTICE LONG LONG!!!!! }
C:每个点处理出该列中以该位置为起点形成的三段是什么样子的。注意第三段长度对第二段取min。然后枚举每一行,找到三段相同且合法的子段计算贡献即可。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 1010 #define mp(x,y) make_pair((x),(y)) char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } typedef pair<char,int> pii; int n,m; pii f[N][N][3]; char a[N][N]; ll ans; bool issame(int i,int x,int y) { for (int j=0;j<3;j++) if (f[i][x][j]!=f[i][y][j]) return 0; return 1; } signed main() { n=read(),m=read(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) a[i][j]=getc(); for (int i=1;i<=m;i++) f[n][i][0]=mp(a[n][i],1); for (int i=n-1;i>=1;i--) for (int j=1;j<=m;j++) if (a[i][j]==a[i+1][j]) { for (int k=0;k<3;k++) f[i][j][k]=f[i+1][j][k]; f[i][j][0].second++; } else { for (int k=1;k<3;k++) f[i][j][k]=f[i+1][j][k-1]; f[i][j][0]=mp(a[i][j],1); } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) f[i][j][2].second=min(f[i][j][2].second,f[i][j][1].second); for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { int t=j; while (t<m&&issame(i,j,t+1)) t++; if (f[i][j][0].second==f[i][j][1].second&&f[i][j][1].second==f[i][j][2].second) ans+=(t-j+1)*(t-j+2)/2; j=t; } } cout<<ans; return 0; //NOTICE LONG LONG!!!!! }
D:可以首先对每个询问二分出该次要加的数的值是多少。然后问题变为多次询问序列中第k个<=p的数是多少。可以将数从小到大考虑,treap维护查询第k大。事实上直接离线即可,开始的二分有点多余。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 500010 #define int long long #define lson tree[k].ch[0] #define rson tree[k].ch[1] char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,q,a[N],b[N],s[N],cnt[N],root,Cnt; struct data { int k,p,i,ans; bool operator <(const data&a) const { return i<a.i; } }Q[N]; bool cmp(const data&a,const data&b) { return a.p<b.p; } vector<int> pos[N]; struct data2{int ch[2],s,p,x; }tree[N]; void up(int k){tree[k].s=tree[lson].s+tree[rson].s+1;} void move(int &k,int p) { int t=tree[k].ch[p]; tree[k].ch[p]=tree[t].ch[!p],tree[t].ch[!p]=k,up(k),up(t),k=t; } void ins(int &k,int x) { if (k==0) {k=++Cnt;tree[k].x=x,tree[k].p=rand(),tree[k].s=1;return;} tree[k].s++; if (tree[k].x<x) {ins(rson,x);if (tree[rson].p>tree[k].p) move(k,1);} else {ins(lson,x);if (tree[lson].p>tree[k].p) move(k,0);} } int query(int k,int x) { if (tree[lson].s+1==x) return tree[k].x; if (tree[lson].s+1>x) return query(lson,x); else return query(rson,x-tree[lson].s-1); } signed main() { srand(time(0)); m=read(),n=read(),q=read(); for (int i=1;i<=m;i++) a[read()]++; for (int i=1;i<=n;i++) pos[a[i]].push_back(i); for (int i=1;i<=n;i++) b[a[i]]++;cnt[0]=b[0]; for (int i=1;i<=m;i++) s[i]=s[i-1]+i*b[i],cnt[i]=cnt[i-1]+b[i]; for (int i=1;i<=q;i++) { Q[i].i=i; int x=read()-m; if (x+m>m*n) Q[i].k=(x+m-1)%n+1,Q[i].p=m; else { int l=0,r=m,p=0; while (l<=r) { int mid=l+r>>1; if (cnt[mid]*mid-s[mid]<x) p=mid,l=mid+1; else r=mid-1; } int k=x-(cnt[p]*p-s[p]); Q[i].k=k,Q[i].p=p; } } sort(Q+1,Q+q+1,cmp); int cur=0; for (int i=0;i<=m;i++) { for (int j:pos[i]) ins(root,j); while (cur<q&&Q[cur+1].p==i) { cur++; Q[cur].ans=query(root,Q[cur].k); } } sort(Q+1,Q+q+1); for (int i=1;i<=q;i++) printf("%d ",Q[i].ans); return 0; //NOTICE LONG LONG!!!!! }
E:E1就是个思博暴力,显然能切就切不会改变可行性。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,b[N<<2],t; int cnt[N<<2]; struct data{int x1,y1,x2,y2; }a[N],c[N]; bool solve(int l,int r) { if (l==r) return 1; for (int i=1;i<=t;i++) cnt[i]=0; for (int i=l;i<=r;i++) cnt[a[i].x1+1]++,cnt[a[i].x2]--; int mx=0,mn=t+1; for (int i=l;i<=r;i++) mx=max(mx,a[i].x1),mn=min(mn,a[i].x2); int s=0,p=-1; for (int i=1;i<=t;i++) { s+=cnt[i]; if (i>=mn&&i<=mx&&s==0) {p=i;break;} } if (p!=-1) { int u=l-1; for (int i=l;i<=r;i++) if (a[i].x2<=p) c[++u]=a[i]; int mid=u; for (int i=l;i<=r;i++) if (a[i].x1>=p) c[++u]=a[i]; for (int i=l;i<=r;i++) a[i]=c[i]; return solve(l,mid)&&solve(mid+1,r); } for (int i=1;i<=t;i++) cnt[i]=0; for (int i=l;i<=r;i++) cnt[a[i].y1+1]++,cnt[a[i].y2]--; mx=0,mn=t+1; for (int i=l;i<=r;i++) mx=max(mx,a[i].y1),mn=min(mn,a[i].y2); s=0,p=-1; for (int i=1;i<=t;i++) { s+=cnt[i]; if (i>=mn&&i<=mx&&s==0) {p=i;break;} } if (p!=-1) { int u=l-1; for (int i=l;i<=r;i++) if (a[i].y2<=p) c[++u]=a[i]; int mid=u; for (int i=l;i<=r;i++) if (a[i].y1>=p) c[++u]=a[i]; for (int i=l;i<=r;i++) a[i]=c[i]; return solve(l,mid)&&solve(mid+1,r); } return 0; } signed main() { n=read(); for (int i=1;i<=n;i++) { b[++t]=a[i].x1=read(); b[++t]=a[i].y1=read(); b[++t]=a[i].x2=read(); b[++t]=a[i].y2=read(); } sort(b+1,b+t+1); t=unique(b+1,b+t+1)-b-1; for (int i=1;i<=n;i++) { a[i].x1=lower_bound(b+1,b+t+1,a[i].x1)-b; a[i].y1=lower_bound(b+1,b+t+1,a[i].y1)-b; a[i].x2=lower_bound(b+1,b+t+1,a[i].x2)-b; a[i].y2=lower_bound(b+1,b+t+1,a[i].y2)-b; } if (solve(1,n)) cout<<"YES";else cout<<"NO"; return 0; //NOTICE LONG LONG!!!!! }
E2的话,基本思路肯定没法有什么变化,如果要保证复杂度,容易想到每次切割都只能花费相当于较少部分矩形个数的代价。那么首先切割时不能把两部分分别递归下去,而是要递归较少的部分并把其从整体中删掉,可以链表实现。然后考虑怎样以这样的复杂度找到一种切割方案。将矩形集合复制成四份,并分别按x1,x2,y1,y2排序,同时处理四份矩形集合,找到一种切割时就立即停止,这样就能保证扫过的部分矩形数量不大于一半了。判断能否切割只需要记录另一维坐标的极值,比如对于x1从小到大排序后,记录x2的最大值即可。实现时像我一样蠢的话就会出现大量的同一份代码写四次。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 100010 #define del(x) {nxt1[pre1[pos1[x]]]=nxt1[pos1[x]];pre1[nxt1[pos1[x]]]=pre1[pos1[x]];nxt2[pre2[pos2[x]]]=nxt2[pos2[x]];pre2[nxt2[pos2[x]]]=pre2[pos2[x]];nxt3[pre3[pos3[x]]]=nxt3[pos3[x]];pre3[nxt3[pos3[x]]]=pre3[pos3[x]];nxt4[pre4[pos4[x]]]=nxt4[pos4[x]];pre4[nxt4[pos4[x]]]=pre4[pos4[x]];} char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n; struct data{int x1,y1,x2,y2,i; }a[N]; bool cmp1(const data&a,const data&b) { return a.x1<b.x1; } bool cmp2(const data&a,const data&b) { return a.x2>b.x2; } bool cmp3(const data&a,const data&b) { return a.y1<b.y1; } bool cmp4(const data&a,const data&b) { return a.y2>b.y2; } bool solve(data *a,int n) { data a1[n+1],a2[n+1],a3[n+1],a4[n+1]; int nxt1[n+2],nxt2[n+2],nxt3[n+2],nxt4[n+2]; int pre1[n+2],pre2[n+2],pre3[n+2],pre4[n+2]; for (int i=0;i<=n;i++) { a[i].i=i; a1[i]=a2[i]=a3[i]=a4[i]=a[i]; nxt1[i]=nxt2[i]=nxt3[i]=nxt4[i]=i+1; pre1[i+1]=pre2[i+1]=pre3[i+1]=pre4[i+1]=i; } sort(a1+1,a1+n+1,cmp1);sort(a2+1,a2+n+1,cmp2);sort(a3+1,a3+n+1,cmp3);sort(a4+1,a4+n+1,cmp4); int pos1[n+2],pos2[n+2],pos3[n+2],pos4[n+2]; for (int i=1;i<=n;i++) pos1[a1[i].i]=i,pos2[a2[i].i]=i,pos3[a3[i].i]=i,pos4[a4[i].i]=i; while (n>1) { int tmp=0; int mxx2=-inf,mnx1=inf,mxy2=-inf,mny1=inf; int cur1=0,cur2=0,cur3=0,cur4=0; bool flag=0; for (int i=1;i<=n/2;i++) { cur1=nxt1[cur1]; cur2=nxt2[cur2]; cur3=nxt3[cur3]; cur4=nxt4[cur4]; mxx2=max(mxx2,a1[cur1].x2); mnx1=min(mnx1,a2[cur2].x1); mxy2=max(mxy2,a3[cur3].y2); mny1=min(mny1,a4[cur4].y1); if (mxx2<=a1[nxt1[cur1]].x1) { flag=1; data b[i+1]; for (int j=1;j<=i;j++) { b[j]=a1[cur1]; int x=a1[cur1].i; cur1=pre1[cur1]; del(x); } if (!solve(b,i)) return 0; else {n-=i;break;} } if (mnx1>=a2[nxt2[cur2]].x2) { flag=1; data b[i+1]; for (int j=1;j<=i;j++) { b[j]=a2[cur2]; int x=a2[cur2].i; cur2=pre2[cur2]; del(x); } if (!solve(b,i)) return 0; else {n-=i;break;} } if (mxy2<=a3[nxt3[cur3]].y1) { flag=1; data b[i+1]; for (int j=1;j<=i;j++) { b[j]=a3[cur3]; int x=a3[cur3].i; cur3=pre3[cur3]; del(x); } if (!solve(b,i)) return 0; else {n-=i;break;} } if (mny1>=a4[nxt4[cur4]].y2) { flag=1; data b[i+1]; for (int j=1;j<=i;j++) { b[j]=a4[cur4]; int x=a4[cur4].i; cur4=pre4[cur4]; del(x); } if (!solve(b,i)) return 0; else {n-=i;break;} } } if (!flag) return 0; } return 1; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(); for (int i=1;i<=n;i++) a[i].x1=read(),a[i].y1=read(),a[i].x2=read(),a[i].y2=read(); if (solve(a,n)) cout<<"YES";else cout<<"NO"; return 0; //NOTICE LONG LONG!!!!! }
小小小小号。result:rank 3 rating +218