[考试反思]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;}
View Code

 

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 }
View Code

 

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 }
View Code

 

posted @ 2020-03-14 22:19  DeepinC  阅读(230)  评论(0编辑  收藏  举报