【考試總結】2022-05-06
魔法球
不難發現是否合法具有單調性,同時保留的一定是權值最大的若干個
通過貪心也可以得到刪去球的順序一定是將待刪去的球從大到小操作,並且在保留球之外被加的是最小的若干個
考察一個 \(\Theta(n)\) 判定方式,即從後向前找到每個球的每個權值的出路:被保留的球和沒被刪去的球,如果出現沒有出路的情況就是非法的
注意相對大小關係發生改變時權值一定是不變的(因為每次新增的是 \(1\)),所以直接從後往前迴圈找到的就是待找出路權值的增量
Code Display
const int N=1e6+10; int n,a[N]; inline bool check(int mid){ int sum=0; for(int i=n-mid;i>=1;--i){ sum+=a[i]; if(sum>(mid+i-1)*(n-mid-i+1)) return 0; } return 1; } signed main(){ freopen("magic.in","r",stdin); freopen("magic.out","w",stdout); int T=read(); while(T--){ n=read(); rep(i,1,n) a[i]=read(); sort(a+1,a+n+1); int l=1,r=n-1,ans=n; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } print(ans); } return 0; }
基因切割
使用 std::bitset
維護每個字母出現的位置,那麼求出來每個 \(T\) 的無交的出現位置就變成了對應字母左移之後進行按位與
那麼找到無交的區間可以使用 bitset->_Find_next(x)
來每次暴跳並刪去
時間複雜度是 \(\Theta\left(\dfrac{n^2}{\omega}\right)\)
題解提供的一種 \(\Theta(n^{\frac{5}3})\) 的做法是維護長度不超過 \(n^{\frac13}\) 的子串的雜湊值,如果 \(T_i\) 超過閥值就暴力掃描
刪去串時有 \(\Theta(B^2)\) 個雜湊值被改變了,所以暴力刪去即可
Code Display
const int N=1e5+10; int n,Q; bitset<N>app[4]; inline int turn(char s){ if(s=='A') return 0; if(s=='C') return 1; if(s=='G') return 2; return 3; } char s[N],t[N]; inline void del(bitset<N>&now,int l,int r){ now^=(now>>(r+1)^(now>>l))<<l; return ; } signed main(){ freopen("dna.in","r",stdin); freopen("dna.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); rep(i,1,n) app[turn(s[i])].set(i); Q=read(); while(Q--){ scanf("%s",t+1); int m=strlen(t+1); bitset<N> now=app[turn(t[1])]; for(int i=2;i<=m;++i) now&=app[turn(t[i])]>>(i-1); vector<pair<int,int> > vec; for(int i=now._Find_first();i!=N;i=now._Find_next(i+m-1)) vec.emplace_back(i,i+m-1); reverse(vec.begin(),vec.end()); for(auto inter:vec){ rep(i,0,3) del(app[i],inter.fir,inter.sec); } n-=m*vec.size(); } for(int i=1;i<=n;++i){ if(app[0][i]) putchar('A'); if(app[1][i]) putchar('C'); if(app[2][i]) putchar('G'); if(app[3][i]) putchar('T'); } putchar('\n'); return 0; }
細菌培養
將所有的 \(0\) 覆蓋的區間進行標記,然後將其視為任意數進行處理其它部分的計算
使用原根處理乘法操作,不難發現本質上就是進行一個 \(a'_i\leftarrow (a_i+a_{i-1}+a_{i+1})\%4\) 的操作
將其寫作 \(\rm OGF\) 即為 \(A\leftarrow A\frac{x^2+x+1}{x}\mod (x^{n}-1)\)
不難發現 \((x^2+x+1)^{2^k}\) 在模 \(4\) 意義下係數有值的位置只有 \(3\) 或 \(5\) 項,對每個 \(k\) 處理即可
Code Display
const int N=1e6+10;
int n,T,a[N],b[N],c[N];
int pwg[5];
signed main(){
freopen("bacteria.in","r",stdin); freopen("bacteria.out","w",stdout);
n=read(); T=read();
auto ins=[&](int l,int r){c[l]++; c[r+1]--;};
pwg[1]=0; pwg[2]=1; pwg[3]=3; pwg[4]=2;
rep(i,0,n-1){
a[i]=read()%5;
if(a[i]==0){
if(T>=n/2){
rep(i,0,n-1) print(0);
putchar('\n');
exit(0);
}else{
if(i-T>=0) ins(i-T,i);
else{
ins(i+n-T,n-1);
ins(0,i);
}
if(i+T<=n) ins(i,i+T);
else{
ins(i,n-1);
ins(0,(i+T)%n);
}
}
}else a[i]=pwg[a[i]];
}
if(T&1){
rep(i,0,n-1) b[i]=a[i];
rep(i,0,n-1) a[i]=(b[i]+b[(i+n-1)%n]+b[(i+1)%n])&3;
}
for(int d=1;(1ll<<d)<=T;++d) if(T>>d&1){
rep(i,0,n-1) b[i]=a[i];
int len=1ll<<d;
int one1=(n-len%n)%n;
int one2=len%n;
int two1=(n-len/2%n)%n;
int two2=len/2%n;
rep(i,0,n-1){
a[i]=(b[i]*3+b[one1]+b[one2]+2*(b[two1]+b[two2]))&3;
one1=(one1+1)%n;
one2=(one2+1)%n;
two1=(two1+1)%n;
two2=(two2+1)%n;
}
}
if(c[0]) print(0);
else print((1<<a[0])%5);
for(int i=1;i<n;++i){
if((c[i]+=c[i-1])) print(0);
else print((1<<a[i])%5);
}
putchar('\n');
return 0;
}