B组题果然是噩梦……
好歹是在一机房待过几天的人,然而B组题每考每炸。
第一场:
第二场:
第三场:
(截屏技术实在不行请大佬见谅)
前两场都各有将近10个200+我都稳定AC100分被kx疯狂dis;
最后一场题巨水AK神巨多而我才刚破百。
还是不要把题想得太复杂了吧。
T1
贪心,傻逼已经不足以形容它。
直接按b-a从大到小排序,直接安排士兵即可。
时空复杂度$Theta(N)$。
大约打了2分钟?
对拍全过了?
结果WA80。
经板B哥哥指点,我把
改成
AC……
因为对拍的暴力只是把sort完的固定顺序改成next_permutation暴枚所有顺序,这句话打的一模一样,所以自然拍不出来。
以后要注意一下子分析全各种情况,还有除了对拍还要稍手摸几组样例了这个。
出题人实在太善良没取max还给80
还有不sort的多测不清空的都能拿80%%%出题人
#include<cstdio> #include<algorithm> using namespace std; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } struct node{ int a,b; }q[100001]; inline int _max(int x,int y){ return x>y?x:y; } int main(){ int T=read(); while(T--){ int n=read(); long long ans(0); for(register int i=1;i<=n;++i)q[i].a=read(),q[i].b=read(); sort(q+1,q+n+1,[](node skyh,node yxs){ return skyh.b-skyh.a>yxs.b-yxs.a; }); for(register int i(1),now(0);i<=n;++i) ans+=_max(q[i].b-now,0),now=_max(q[i].b,now)-q[i].a; printf("%lld ",ans); } return 0; }
T2
应该是本场考试唯一有些难度的题。
有些思维含量,于是乎我就想不出来了。
考场上一直在想二项式反演,我怕是脑抽了……
这个题放在文化课里其实也是一个很棒的题。
考虑把${C_n^i}^2$转换成$C_n^i imes C_n^{n-i}$。
相当于有2n个物品,先在前n个物品选i个,后n个物品选n-i个。
由于$iin[0,n]$,所以方案数之和等价于在直接在2n个物品里选n个的方案数。
预处理阶乘和逆元,对于每个询问输出$C_{2n}^n$即可。
时间复杂度$Theta(N+T)$。
空间复杂度$Theta(N)$,注意数组开到数据范围的2倍,阶乘逆元也要递推到数据范围的2倍。
还挺不错的,可惜只能给我这种眼浊的人做,不然一打表就看出来了。
#include<cstdio> #define ll long long using namespace std; int const N=2e6+1,mod=1e9+7; int n; ll fac[N],inv[N]; inline int read(){ int ss(0);char bb=getchar(); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline ll power(ll x,int y){ ll ans(1); for(;y;y>>=1,x=x*x%mod) if(y&1)ans=ans*x%mod; return ans; } inline ll C(int x,int y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; } int main(){ fac[0]=fac[1]=1; for(register int i=2;i<N;++i)fac[i]=fac[i-1]*i%mod; inv[N-1]=power(fac[N-1],mod-2); for(register int i=N-1;i;--i)inv[i-1]=inv[i]*i%mod; int T=read(); while(T--) n=read(),printf("%lld ",C(n<<1,n)); return 0; }
T3
以前做过一道类似的题,Hash二分给我的印象很深刻,所以我上来就打……
通过Hash二分和差分可以在$Theta(NlogN)$的时间内可以求出$[1,r],rin[1,n]$区间内的回文串个数,设为w[r](还可以求出以r为结尾的回文串数量ed[r])。
一开始我想的很简单,对于询问(l,r)直接w[r]-w[l-1]。
但如果设左端点是le,右端点是re的话,这样会多出$lein[1,l),rein[l,r]$的情况。
所以我又用$Theta(N^2)$的时间处理出区间[1,r]中经过l的回文串数量ps[l][r]。
那么对于询问(l,r)答案就是w[r]-w[l-1]-ps[l-1][r]+ed[l-1]。
时空复杂度$Theta(N^2)$。
然而因为需要$Theta(N^2)$处理出ps数组,所以二分Hash失去意义,还不如直接区间DP出答案……
直接套树状数组$Theta(N^2logN)$也能过而且代码巨短还比正解快。
反正我的做法肯定是最SB的了,不过幸好还是AC了。
#include<cstdio> #define ull unsigned long long #define ll long long using namespace std; int const N=5005; ull const p=23333; ull b[N],h1[N],h2[N]; int n; int cf[N],w[N],ed[N]; int ps[N][N]; char s[N]; inline int read(){ int ss(0);char bb=getchar(); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int min(int x,int y){ return x<y?x:y; } inline ull cal1(int l,int r){ return h1[r]-h1[l]*b[r-l]; } inline ull cal2(int l,int r){ return h2[r]-h2[l]*b[l-r]; } int main(){ b[0]=1; register char bb=getchar(); while(bb<'a'||bb>'z')bb=getchar(); for(;bb>='a'&&bb<='z';bb=getchar()) s[++n]=bb,b[n]=b[n-1]*p,h1[n]=h1[n-1]*p+bb; for(register int i=n;i;--i) h2[i]=h2[i+1]*p+s[i]; for(register int i=1;i<=n;++i){ int l=0,r=min(i-1,n-i); while(l<r){ int mid=l+r+1>>1; if(cal1(i-mid-1,i+mid)==cal2(i+mid+1,i-mid))l=mid; else r=mid-1; } ++cf[i],--cf[i+l+1]; for(register int j=i-l;j<i;++j)++ps[j][(i<<1)-j],--ps[j][i+l+1]; for(register int j=i;j<=i+l;++j)++ps[j][j],--ps[j][i+l+1]; if(i==n||s[i]!=s[i+1])continue; l=0,r=min(i-1,n-i-1); while(l<r){ int mid=l+r+1>>1; if(cal1(i-mid-1,i+mid+1)==cal2(i+mid+2,i-mid))l=mid; else r=mid-1; } ++cf[i+1],--cf[i+l+2]; for(register int j=i-l;j<=i;++j)++ps[j][(i<<1)-j+1],--ps[j][i+l+2]; for(register int j=i+l+1;j>i;--j)++ps[j][j],--ps[j][i+l+2]; } for(register int i=1,ct=0;i<=n;++i) ct+=cf[i],w[i]=w[i-1]+(ed[i]=ct); for(register int i=1;i<=n;++i) for(register int j=1,ct=0;j<=n;++j) ct+=ps[i][j],ps[i][j]=ps[i][j-1]+ct; int T=read(); while(T--){ int l=read(),r=read(); if(l>r){puts("0");continue;} //printf("%d %d %d %d ",w[r],w[l-1],ps[l-1][r],ed[l-1]); printf("%d ",w[r]-w[l-1]-ps[l-1][r]+ed[l-1]); } return 0; }