A
签到
#include<bits/stdc++.h> using namespace std; int T,n; char s[10001]; int main() { scanf("%d",&T);while(T--) { scanf("%d",&n); scanf("%s",s+1); int ans=0; for(int i=1;i+10<=n;i++) if(s[i]=='8'){ans=1;break;} if(ans)puts("YES");else puts("NO"); } }
B
交互开始打错个地方WA了一发。不知道为什么给6个数,实际上能给7个两两乘积互不相同的数的。就是“? 1 2”“? 2 3”可以求解一个三元组,讨论一下即可,后一个三元组同理。
#include<bits/stdc++.h> using namespace std; int a[7]={0,4,8,15,16,23,42},ax[1100],ay[1100],b[7]; int main() { for(int i=1;i<6;i++) for(int j=i+1;j<=6;j++) ax[a[i]*a[j]]=i,ay[a[i]*a[j]]=j; int x,y; puts("? 1 2"),fflush(stdout); cin>>x; puts("? 2 3"),fflush(stdout); cin>>y; b[1]=ax[x],b[2]=ay[x]; if(ax[y]==b[1]||ay[y]==b[1])swap(b[1],b[2]); if(ax[y]==b[2])b[3]=ay[y];else b[3]=ax[y]; puts("? 4 5"),fflush(stdout); cin>>x; puts("? 5 6"),fflush(stdout); cin>>y; b[4]=ax[x],b[5]=ay[x]; if(ax[y]==b[4]||ay[y]==b[4])swap(b[4],b[5]); if(ax[y]==b[5])b[6]=ay[y];else b[6]=ax[y]; printf("!"); for(int i=1;i<=6;i++)printf(" %d",a[b[i]]); }
C
签到
#include<bits/stdc++.h> using namespace std; const int N=5e5+7; int n,m,fa[N],sz[N]; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)fa[i]=i; while(m--) { int cnt,x,y,u,v; scanf("%d",&cnt); if(!cnt)continue; scanf("%d",&x); for(int i=1;i<cnt;i++) { scanf("%d",&y); u=find(x),v=find(y); if(u!=v)fa[u]=v; } } for(int i=1;i<=n;i++)sz[find(i)]++; for(int i=1;i<=n;i++)printf("%d ",sz[find(i)]); }
D
读错了题意WA了N发,耽误大量时间,甚至影响了写E的心态。看成了使两串尽可能等长,还在那找性质。实际上就是个SB贪心题,就是(给前缀和小的,)给前缀和大的。
#include<bits/stdc++.h> using namespace std; const int N=2e5+7; int n,ans,sl,sr; char s[N]; int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;i++) if(s[i]=='(') { if(sl<sr)printf("0"),sl++; else printf("1"),sr++; } else if(sl>sr)printf("0"),sl--; else printf("1"),sr--; }
E
写D写得心态爆炸,然后又WA无穷发。然后特判原数列递增的情况,就是怎么删都可以。其余的情况,对于每个值,直接记录前缀最大位置和后缀最小位置,two-pointers扫一遍即可。不过要注意讨论值域内没出现的值的情况,我因为这个调了+WA了好多发。
#include<bits/stdc++.h> using namespace std; const int N=1e6+7; int n,lim,a[N],mn[N],mx[N],suf[N]; long long ans; int main() { scanf("%d%d",&n,&lim); for(int i=1;i<=lim;i++)mn[i]=n+1; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); mn[a[i]]=min(mn[a[i]],i); mx[a[i]]=max(mx[a[i]],i); } int L=lim,R=1,pre=mx[1]; for(int i=1;i<lim;i++) { pre=max(pre,mx[i]); if(pre>mn[i+1]){L=i;break;} } if(L==lim){cout<<1ll*lim*(lim+1)/2;return 0;} pre=mn[lim]; for(int i=lim;i>1;i--) { pre=min(pre,mn[i]); if(mx[i-1]>pre){R=i;break;} } ans=lim-R+2; suf[lim]=mn[lim]; for(int i=lim-1;i>=R;i--)suf[i]=min(suf[i+1],mn[i]); pre=mx[1]; for(int i=1,j=R;i<=L;i++) { pre=max(pre,mx[i]); if(j<=i)j=i+1; while(j<=lim&&pre>suf[j])j++; ans+=lim-j+2; if(j==i+1)ans--; } cout<<ans; }
F
其实是道比较简单的对每个位置分开求贡献,但因为太热了被D搞到心态爆炸没去写F了。实际上可以这么做:发现对于a[i]只有比a[i]小的数字才会对a[i]产生的贡献造成影响,按照从小到大的顺序加入数字,发现:a[i]区间贡献为i(n-i+1)a[i],a[i]左边小于等于a[i]的a[j]贡献为Σj(n-i+1)a[i],a[i]右边大于a[i]的a[j]贡献为Σi(n-j+1)a[i],然后这个显然可以维护前缀树状数组和后缀树状数组查询一下就结束了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+7,mod=1e9+7; struct node{int x,id;}a[N]; int n,ans,c1[N],c2[N]; bool cmp(node a,node b){return a.x<b.x;} void add(int*c,int x,int v){while(x<=n)c[x]=(c[x]+v)%mod,x+=x&-x;} int ask(int*c,int x){int ret=0;while(x)ret=(ret+c[x])%mod,x-=x&-x;return ret;} int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i].x),a[i].id=i; sort(a+1,a+n+1,cmp); for(int i=1,p;i<=n;i++) { p=a[i].id; ans=(ans+(1ll*p*(n-p+1)+1ll*(n-p+1)*ask(c1,p-1)+1ll*p*(ask(c2,n)-ask(c2,p)+mod))%mod*a[i].x)%mod; add(c1,p,p),add(c2,p,n-p+1); } printf("%d",ans); }
G
太热了不讲了。
result:用小小号(OIerDb)打的,rank159,rating+=29,罚时共8发,感觉是个5题的人名次都在我上面,这竟然都能涨rating?