因为是unrated于是就叫划水记了,而且本场也就用了1h左右。
A、B:划水去了,没做
C:大水题,根据初三课本中圆的知识,可以把角度化成弧长,而这是正多边形,所以又可以化成边数,于是假设读入为a,就是周长的a/180,gcd一下就行了,注意如果a/b这个分数满足a+1=b,那么就要ans*=2
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; int main() { int T;scanf("%d",&T); while(T--) { int n,t,fm,fz; scanf("%d",&n); if(n==90){puts("4");continue;} t=__gcd(n,180); fm=180/t,fz=n/t; if(fz+1==fm)fm*=2; printf("%d\n",fm); } }
D:首先不是h、a、r、d的字符可以删去,不用管它,而我们可以做个dp,f[i][0/1/2/3/4]表示当前位置匹配了前0/1/2/3/4个以后的最小代价
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+7; int n,m,v[N],a[N],C[N]; ll f[N][5],ans; char s[N]; int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;i++)scanf("%d",&a[i]); C['h']=1,C['a']=2,C['r']=3,C['d']=4; for(int i=1;i<=n;i++) if(C[s[i]])v[++m]=C[s[i]],a[m]=a[i]; for(int i=1;i<=m;i++)for(int j=0;j<5;j++)f[i][j]=1e18; for(int i=1;i<=m;i++) for(int j=0;j<5;j++) { if(j==v[i]-1)f[i][j]=min(f[i][j],f[i-1][j]+a[i]); else f[i][j]=min(f[i][j],f[i-1][j]); if(j==v[i])f[i][j]=min(f[i][j],f[i-1][j-1]); } ans=1e18; for(int j=0;j<4;j++)ans=min(ans,f[m][j]); printf("%lld",ans); }
E:本场切的人数最少的题,现场当然没有想到怎么做。由于是期望,肯定是求合法方案数/总方案数,总方案数好求就是一个组合数,考虑求合法方案数。由于总分、人数范围都比较小,考虑枚举Hasan的得分,然后进行计算即可。计算过程大概就是个容斥的过程。复杂度O(玄学),总之范围小能通过就行了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; const int mod=998244353; int p,s,r,sum,c[5222][107]; int qpow(int a,int b) { int ret=1; while(b) { if(b&1)ret=1ll*ret*a%mod; a=1ll*a*a%mod,b>>=1; } return ret; } int calc(int n,int m,int x) { int ret=0; for(int i=0;i<=m&&x*i<=n;i++) { int add=1ll*c[m][i]*c[n-x*i+m-1][m-1]%mod; if(i&1)ret=(ret-add+mod)%mod; else ret=(ret+add)%mod; } return ret; } int main() { scanf("%d%d%d",&p,&s,&r); if(p==1){puts("1");return 0;} for(int i=0;i<=5200;i++) { c[i][0]=1; for(int j=1;j<=i&&j<=100;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } for(int x=r;x<=s;x++) if(x*p>=s) for(int i=1;i<=p;i++) if(i*x<=s&&(p-i)*(x-1)+x*i>=s) { if(i==p)sum=(sum+(x*i==s?qpow(i,mod-2):0))%mod; sum=(sum+1ll*c[p-1][i-1]*calc(s-x*i,p-i,x)%mod*qpow(i,mod-2))%mod; } sum=1ll*sum*qpow(c[s-r+p-1][p-1],mod-2)%mod; printf("%d",sum); }
F:又是一道期望题,其实还是不太难,可以把答案分成三类:1、两者都在原有序列。2、两者都在-1上。3、一个在-1上一个在原有序列。第一类可以用归并排序求解逆序对,第二类直接记录状态f[i]=f[i-1]+(i-1)/2,考虑插入最大的即可。第三类也很好求,记录每个位置前面有多少空当,比当前数小的有几个数没有出现,这个都可以前缀和O(1)求得,然后枚举每个不为-1的位置,答案分成两部分:1、前面的空当数/总空当数*比该数大的没填的个数。2、后面的空当数/总空当数*比该数小的没填的个数。为什么呢?每个数分到前/后的机会是均等的,考虑随机性即可,不能把问题想复杂。复杂度O(nlogn),瓶颈在于归并排序
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; const int N=2e5+7,mod=998244353; int n,m,ans,p[N],a[N],b[N],c[N],sp[N],sv[N],inv[N],f[N]; void merge(int l,int r) { if(l>=r)return; int m=(l+r)/2,i,j,n1=m-l+1,n2=r-m; merge(l,m);merge(m+1,r); for(i=1;i<=n1;i++)b[i]=a[l+i-1]; for(i=1;i<=n2;i++)c[i]=a[m+i]; i=j=1;b[n1+1]=c[n2+1]=1e9; for(int k=l;k<=r;k++) if(b[i]<=c[j])a[k]=b[i++]; else a[k]=c[j++],ans=(ans+n1-i+1)%mod; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)sv[i]=1; for(int i=1;i<=n;i++) { scanf("%d",&p[i]); sp[i]=sp[i-1]; if(p[i]>0)a[++m]=p[i],sv[p[i]]=0; else sp[i]++; } for(int i=1;i<=n;i++)sv[i]+=sv[i-1]; inv[0]=inv[1]=1; for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; for(int i=2;i<=n;i++)f[i]=(f[i-1]+1ll*(i-1)*inv[2])%mod; merge(1,m); ans=(ans+f[n-m])%mod; for(int i=1;i<=n;i++) if(p[i]>0) { int P=1ll*(sv[n]-sv[p[i]])*sp[i-1]%mod*inv[sp[n]]%mod; ans=(ans+P)%mod; P=1ll*sv[p[i]-1]*(sp[n]-sp[i])%mod*inv[sp[n]]%mod; ans=(ans+P)%mod; } printf("%d",ans); }
G:弱智题没写出来,第二天早上一看就会,是不是晚上智商有debuff水平低啊。题解:没什么好讲的,每次只有+指定是数才可以,n次可以NTT转移(我都想到了NTT还不会)没写出来的原因:想复杂问题,每次还倍增,硬生生的把复杂度从O(9nlogn)->O(9nlog2n),其实NTT(a,1)后,对a数组直接乘n次方再NTT(a,-1)就行了
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; const int N=2098000,p=998244353; int n,k,a[N],R[N],ans; int qpow(int a,int b) { int ret=1; while(b) { if(b&1)ret=1ll*ret*a%p; a=1ll*a*a%p,b>>=1; } return ret; } void NTT(int*a,int n,int typ) { for(int i=1;i<n;i++) { R[i]=(R[i>>1]>>1)|((i&1)*(n>>1)); if(i<R[i])swap(a[i],a[R[i]]); } for(int i=1;i<n;i<<=1) { int wn=qpow(3,typ*(p/(i*2))+p-1); for(int j=0;j<n;j+=i*2) for(int k=0,w=1;k<i;k++,w=1ll*w*wn%p) { int x=a[j+k],y=1ll*w*a[j+k+i]%p; a[j+k]=(x+y)%p; a[j+k+i]=(x-y+p)%p; } } if(typ==1)return; int invn=qpow(n,p-2); for(int i=0;i<n;i++)a[i]=1ll*a[i]*invn%p; } int main() { scanf("%d%d",&n,&k); n/=2; for(int i=1,x;i<=k;i++)scanf("%d",&x),a[x]=1; int nn=1; while(nn<=n*18)nn<<=1; NTT(a,nn,1); for(int i=0;i<nn;i++)a[i]=qpow(a[i],n); NTT(a,nn,-1); for(int i=0;i<=n*9;i++)ans=(ans+1ll*a[i]*a[i])%p; printf("%d",ans); }