[考试反思]0314省选模拟45:偏离
又一次把重点放错了题。$T2$没想出的情况下没怎么弄$T3$然而实际上$T3$的部分分最肥。
然后总分就崩了。$T2$写了个神奇的莫队,然而出题人并没有想到这个然后没有留分,结果比暴力还惨。
$T1$倒是比期望高了一点。但是也差不多吧。
以为还是一如既往的过百即稳。。。然而其实只是题简单。
我感觉我像个弱智,$T2$都想到离线了为啥先想到的是莫队???
脑子里的乱搞思想太多,反而掩盖了正解。。。
要相信自己能想出来啊,还有抢救的机会啊啊啊
T1:mxtrix
大意:求所有子矩阵的权值和。定义为本质不同的行数。$nm \le 5 \times 10^5$
所以其实我们只在意每个串作为多少个矩阵的这种串的第一次出现。
大概是个扫描线?左端点不断向右移动然后考虑增量的变化。
最开始就相当与对于建一个$trie$然后在每个节点上维护在哪些串里出现过,每次插入时产生影响的就是前驱后继。
然后考虑左端点右移会发生什么,就是把$trie$的根扔掉然后所有儿子合并起来当新的根。
启发式就行了。$O(nm \ log^2n)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 1111111 4 int n,m,rt,pc,v[S];long long ans,rate; 5 set<int>s[S];unordered_map<int,int>M[S]; 6 int read(){char ch=getchar();int p=0;while(!isdigit(ch))ch=getchar();while(isdigit(ch))p=p*10+ch-48,ch=getchar();return p;} 7 void ins(int p,int w){ 8 if(s[p].find(w)!=s[p].end())return; 9 auto i=s[p].lower_bound(w);int x=*(--i); i++; s[p].insert(w); rate+=(w-x)*(n-w+1ll); 10 if(i!=s[p].end())rate-=(w-x)*(n-(*i)+1ll); 11 } 12 void insert(int&p,int o,int l){ 13 if(!p)p=++pc,s[pc].insert(0); ins(p,o); 14 if(l)insert(M[p][read()],o,l-1); 15 } 16 void delctb(int p,int lst=0){for(auto x:s[p])rate-=(x-lst)*(n-x+1ll),lst=x;} 17 void merge(int&p1,int p2){ 18 if(!p1){p1=p2;return;} 19 if(s[p2].size()>s[p1].size())swap(s[p1],s[p2]); 20 delctb(p2); for(auto x:s[p2])ins(p1,x); s[p2].clear(); 21 for(auto x:M[p2])merge(M[p1][x.first],x.second); M[p2].clear(); 22 } 23 void delrt(){ 24 int c=0;delctb(rt);s[rt].clear(); 25 ans+=rate; int R=rt; 26 if(m)for(auto x:M[R])if(!c)rt=x.second,c=1;else merge(rt,x.second); M[R].clear(); 27 } 28 int main(){cin>>n>>m;for(int i=1;i<=n;++i)insert(rt,i,m);while(m--)delrt();cout<<ans;}
T2:sequence
大意:序列,多次询问子串$[l,r]$有多少子串满足区间按位与是$k$的倍数。$n \le 10^5,q \le 5 \times 10^5$
离线,扫描线。
后缀按位与每次只会变化$log$次,所以往前跳同时线段树区间加就行。
复杂度$O(nlog^n+qlogn)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 100005 4 int n,qn,k,a[S],Lst[30][S],q[33];long long v[S<<2],Ans[5*S],lz[S<<2]; 5 struct Q{int l,r,o;}qs[S*5]; 6 #define lc p<<1 7 #define rc lc|1 8 #define md (cl+cr>>1) 9 void add(int l,int r,int p=1,int cl=1,int cr=n){ 10 if(l<=cl&&cr<=r){v[p]+=cr-cl+1;lz[p]++;return;} 11 if(l<=md)add(l,r,lc,cl,md);if(r>md)add(l,r,rc,md+1,cr); 12 v[p]=v[lc]+v[rc]; 13 } 14 long long ask(int l,int r,int p=1,int cl=1,int cr=n){ 15 if(l<=cl&&cr<=r)return v[p]; 16 if(lz[p])lz[lc]+=lz[p],lz[rc]+=lz[p],v[lc]+=(md-cl+1)*lz[p],v[rc]+=(cr-md)*lz[p],lz[p]=0; 17 return (l<=md?ask(l,r,lc,cl,md):0)+(r>md?ask(l,r,rc,md+1,cr):0); 18 } 19 int main(){ 20 cin>>n>>qn>>k; 21 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 22 for(int i=1;i<=qn;++i)scanf("%d%d",&qs[i].l,&qs[i].r),qs[i].o=i; 23 sort(qs+1,qs+1+qn,[](Q x,Q y){return x.r<y.r;}); 24 for(int i=1;i<=n;++i)for(int j=0;j<30;++j)Lst[j][i]=a[i]&1<<j?Lst[j][i-1]:i; 25 for(int i=1,pt=1;i<=n;++i){ 26 int c=0,lp=i,num=a[i]; 27 for(int x=0;x<30;++x)if(num&1<<x)q[++c]=Lst[x][i]; 28 sort(q+1,q+1+c); 29 for(int x=c;~x;--x)if(lp!=q[x]){ 30 if(num%k==0)add(q[x]+1,lp); 31 num&=a[q[x]];lp=q[x]; 32 } 33 while(qs[pt].r==i)Ans[qs[pt].o]=ask(qs[pt].l,i),pt++; 34 } 35 for(int i=1;i<=qn;++i)printf("%lld\n",Ans[i]); 36 }
T3:permutation
大意:从左往右满足是出现过的最大值的有$a$个,从右往左有$b$个,长度为$n$的排列数。$n \le 2 \times 10^5$
抽象题意,发现就是指定最大值的位置后,左边划分为$a-1$个环,右边$b-1$个。
环之间顺序固定(换内最大值由小到大),环的断开点确定(最大值靠近全局最大值)。
然后组合含义出发,除$n-1$外所有数分成$a+b-2$个环,再选出$a-1$个放在左边。
所以只需要预处理斯特林数,一行就行。用到的是那个$\prod\limits_{i=0}^{n-1} (x+i)=\sum\limits_{i=0}^{n} x^i S(n,i)$
然后老套路分治一边求另一边就行了。时间复杂度$O(nlogn)$。毒瘤出题人喜闻乐见卡常卡掉$std$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 998244353 4 #define S 1<<20 5 int fac[S],inv[S],len,rev[S],a[S],b[S],r[S],pw[S]; 6 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 7 void setlen(int n){ 8 len=1;while(len<=n)len<<=1; 9 for(int i=1;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0); 10 } 11 void NTT(int*a,int op=1){ 12 for(int i=1;i<len;++i)if(rev[i]>i)swap(a[rev[i]],a[i]); 13 for(int i=1;i<len;i<<=1)for(int j=0,w=qp(3,(mod-1)/2/i*op+mod-1);j<len;j+=i<<1) 14 for(int k=j,t=1,x,y;k<i+j;++k,t=1ll*t*w%mod) 15 x=a[k],y=1ll*a[k+i]*t%mod,a[k]=(x+y)%mod,a[k+i]=(x-y+mod)%mod; 16 if(op<0)for(int i=0,iv=qp(len,mod-2);i<len;++i)a[i]=1ll*a[i]*iv%mod; 17 } 18 void solve(int n){ 19 if(!n){a[0]=1;return;} 20 int L=n>>1; solve(L); setlen(n); 21 for(int i=0;i<len;++i)r[i]=b[i]=0; 22 pw[0]=1; 23 for(int i=1;i<=L;++i)pw[i]=pw[i-1]*1ll*L%mod; 24 for(int i=0;i<=L;++i)r[i]=a[i]*1ll*fac[i]%mod; 25 for(int i=0;i<=L;++i)b[L-i]=pw[i]*1ll*inv[i]%mod; 26 NTT(r);NTT(b); for(int i=0;i<len;++i)b[i]=1ll*b[i]*r[i]%mod; NTT(b,-1); 27 for(int i=0;i<=L;++i)b[i]=b[i+L]*1ll*inv[i]%mod; 28 for(int i=L+1;i<len;++i)b[i]=0; 29 NTT(a);NTT(b); for(int i=0;i<len;++i)a[i]=1ll*a[i]*b[i]%mod; NTT(a,-1); 30 if(n&1){ 31 for(int i=n;i;--i)a[i]=((n-1ll)*a[i]+a[i-1])%mod; 32 a[0]=a[0]*(n-1ll)%mod; 33 } 34 } 35 int main(){ 36 int n,A,B; 37 cin>>n>>A>>B; 38 for(int i=fac[0]=1;i<=n;++i)fac[i]=fac[i-1]*1ll*i%mod; 39 inv[n]=qp(fac[n],mod-2); 40 for(int i=n-1;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod; 41 solve(n-1); 42 printf("%lld\n",1ll*a[A+B-2]*fac[A+B-2]%mod*inv[A-1]%mod*inv[B-1]%mod); 43 }