[考试反思]0505省选模拟88:滑稽
假黄名祭。
$T1$数据锅了于是让$skyh$重制数据,他为了$fake$所以把数据弄得很强然后把自己考场代码卡常了。
但是不管怎么说我$T1$能爆炸成这样也是太蠢了。。。在这人均$50$且我还砸时间想到了$72$的题上(而且原数据$72$写出来卡卡常就是$100$
结果写的时候线性基写错了(也有一部分是性质理解不深刻或者说干脆就没动脑子)然后就直接挂的只剩签到分。
$T2$写了个低智离散化+搜索但不知道为啥别人都没写。虽说最后正解也挺低智的。
但是就算正解低智我还调了好久好久各类细节,极度自闭。$cbx24min$就切了。
$T3$倒是一个比较中规中矩的题,看部分分想乱搞卡常的时候把复杂度莫名其妙卡下来了,就很开心。
总之又因为低错挂了几十分这样。真是蠢到一定境界。我没脑子可能断电了。。。
T1:也许
大意:维护集合$S$和一个图,图中点编号$\in [0,2^n)$。满足如果$(x \ xor \ y )\in S$则边$(x,y)$存在于图中。支持插入删除。
每次操作后回答图中联通块数。$n \le 30,Q \le 2 \times 10^6$
发现题意就是线性基。如果线性基大小为$size$则$ans=2^{n-size}$
然后就是离线线性基的板子题。遇到删除时间更早的数就交换就行了。$O(nQ)$
写这题的时候理解了$fread$原理。。。我好闲啊(?)
1 #include<cstdio> 2 const int S=1<<21,P=11111117; 3 char ibuf[S],*iS,*iT; 4 #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,S,stdin),(iS==iT?EOF:*iS++)):*iS++) 5 int in(){int p=0;char ch=gc();for(;ch<48||ch>57;ch=gc());for(;ch>47&&ch<58;ch=gc())p=p*10+ch-48;return p;} 6 void swap(int&a,int&b){a^=b^=a^=b;} 7 struct hash_map{ 8 int fir[P],l[P],to[P],v[P],ec; 9 int&operator[](int x){int r=x%P; 10 for(int i=fir[r];i;i=l[i])if(to[i]==x)return v[i]; 11 l[++ec]=fir[r];fir[r]=ec;to[ec]=x;return v[ec]; 12 } 13 }M; 14 int n,q,et[S],op[S],a[S],p[32],ans,b[32]; 15 int main(){ 16 n=in();q=in(); 17 for(int i=1;i<=q;++i){ 18 op[i]=in(),a[i]=in(); et[i]=q+1; 19 if(op[i]==1)M[a[i]]=i; 20 else et[M[a[i]]]=i; 21 } 22 for(int i=1;i<=q;++i){ 23 if(op[i]==1){ 24 int x=a[i],y=i; 25 for(int j=29;~j;--j)if(x&1<<j)if(et[p[j]]<et[y])swap(p[j],y),swap(x,b[j]),x^=b[j]; 26 else x^=b[j]; 27 }int cnt=0;for(int j=29;~j;--j)if(et[p[j]]>i)cnt++;else p[j]=b[j]=0; 28 ans^=1<<n-cnt; 29 }printf("%d\n",ans); 30 }
T2:这就是
大意:图,点带权$0 \le W_i \le R_i$。给定$R$求所有图中,每种图的点权数字种数的和。$n\le 15,R \le 10^9$
若是完全图则数字两两不相等。你显然会把$R$排序后直接$n \prod (R_i +1 -i)$
否则状压,$dp[i][j]$表示点集$i$已选,出现了$j$种数。转移时枚举一个集合填上相同的数。
为了不重不漏且答案正确需要钦定新增点集包含原有集合的补集中,$(R,id)$双关键字下最小的点。
$O(3^nn)$。挺神仙的。一个钦定想了半小时。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 1<<15 4 #define mod 1000000007 5 int mn[S],dp[S],n,m,ans,r[17],g[S]; 6 int main(){ 7 scanf("%d%d",&n,&m); 8 for(int i=1;i<1<<n;++i)mn[i]=mod; 9 for(int i=0;i<n;++i)scanf("%d",&r[i]); 10 for(int i=1;i<1<<n;++i)for(int j=0;j<n;++j)if(i&1<<j)mn[i]=min(mn[i],r[j]+1); 11 for(int i=1,a,b;i<=m;++i){ 12 scanf("%d%d",&a,&b);a--;b--; 13 for(int j=1;j<1<<n;++j)if(j&1<<a&&j&1<<b)mn[j]=0; 14 } 15 for(int i=1;i<1<<n;++i){ 16 int x=mod; 17 for(int j=0;j<n;++j)if(i&1<<j&&x>r[j])g[i]=j,x=r[j]; 18 } 19 dp[0]=1; 20 for(int i=0;i<n;++i){ 21 for(int j=(1<<n)-1;~j;--j){ 22 dp[j]=0; 23 for(int k=j;k;k=k-1&j)if(k&1<<g[(1<<n)-1^(j^k)])dp[j]=(dp[j]+1ll*dp[j^k]*max(mn[k]-i,0))%mod; 24 }ans=(ans+dp[(1<<n)-1]*(1ll+i))%mod; 25 }printf("%d\n",ans); 26 }
T3:人生吧
大意:给定数列$A$多次询问区间$[l,r]$的所有非空子集的$gcd$的积。$n,q,A \le 10^5$
部分分的数据范围大力提示莫队。然后对于$gcd$的积这东西我们可以用$p^e$做$p$贡献这个老套路。
具体而言若$p^e$在区间中出现了$x$次则答案乘上$p^{2^x-1}$
可以直接莫队了。预处理每个数包含哪些$p^e$可以做到$O(n\sqrt{n} log \ n)$是可以通过的。
细节方面只要用$vector$维护每种$p$的贡献及其逆元(用到哪处理到哪不要全弄出来)
然后莫队修改的时候只要乘原值逆元乘新值即可。贡献$f(x)=f(x-1)^2 \times p$可以直接$O(1)$递推,逆元也是,都不需要快速幂。
然后还可以发现,想把最后一个$log$卡满的话一定是$p^e$中$p$很小$e$很大。
那么只要对于$p<a$的特殊处理,处理出这些$p^e$的数字的出现次数的前缀和即可快速查询区间。
对于小的$p$把每种$p$的贡献也都求出来,还是递推就行。
复杂度就是$O(q\sqrt{n} log_a A + nalog_a A + qalog_a A)$。取$a=25$即可通过。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 100005 4 #define mod 998244353 5 struct qs{int l,r,o;friend bool operator<(qs x,qs y){int X=x.l/400,Y=y.l/400;return X^Y?X<Y:(X&1^x.r<y.r);}}Q[S]; 6 int A[S],n,q,iv[S],ans[S],Ans=1,ctb[S],np[S],p[S],pc,cnt[S]; 7 vector<int>d[S],C[S],iC[S],EX,pre[S]; 8 void chg(int x,int w){ 9 int v=ctb[x];int &N=cnt[x]; N+=w; 10 if(N>=C[v].size())C[v].push_back(C[v][N-1]*1ll*C[v][N-1]%mod*v%mod),iC[v].push_back(iC[v][N-1]*1ll*iC[v][N-1]%mod*iv[v]%mod); 11 Ans=1ll*Ans*C[v][N]%mod*iC[v][N-w]%mod; 12 } 13 void mdf(int x,int w){for(int i=0;i<d[x].size();++i)chg(d[x][i],w);} 14 int EXcal(int l,int r,int a=1){ 15 for(int i=0;i<EX.size();++i)a=1ll*a*C[ctb[EX[i]]][pre[EX[i]][r]-pre[EX[i]][l-1]]%mod; 16 return a; 17 } 18 int main(){ 19 iv[1]=1; for(int i=2;i<S;++i)iv[i]=mod-mod/i*1ll*iv[mod%i]%mod; 20 for(int i=2;i<S;++i){ 21 if(!np[i])p[++pc]=ctb[i]=i,C[i].push_back(1),iC[i].push_back(1),C[i].push_back(i),iC[i].push_back(iv[i]); 22 for(int j=1,x;(x=p[j]*i)<S;++j) 23 if(i%p[j])np[x]=1; 24 else{ctb[x]=ctb[i];np[x]=1;break;} 25 } 26 for(int i=2;i<S;++i)if(ctb[i]>25)for(int j=i;j<S;j+=i)d[j].push_back(i); else if(ctb[i])EX.push_back(i); 27 scanf("%d%d",&n,&q); 28 for(int i=1;i<=n;++i)scanf("%d",&A[i]); 29 for(int i=0;i<EX.size();++i){ 30 int D=EX[i]; pre[D].resize(n+1); 31 for(int j=1;j<=n;++j)pre[D][j]=pre[D][j-1]+(A[j]%D==0); 32 if(np[D])continue; C[D].resize(n+1); 33 for(int j=2;j<=n;++j)C[D][j]=1ll*C[D][j-1]*C[D][j-1]%mod*D%mod; 34 } 35 for(int i=1;i<=q;++i)scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].o=i; 36 sort(Q+1,Q+1+q); 37 int l=1,r=0; 38 for(int i=1;i<=q;++i){ 39 while(r<Q[i].r)mdf(A[++r],+1); 40 while(l>Q[i].l)mdf(A[--l],+1); 41 while(r>Q[i].r)mdf(A[r--],-1); 42 while(l<Q[i].l)mdf(A[l++],-1); 43 ans[Q[i].o]=Ans*1ll*EXcal(l,r)%mod; 44 } for(int i=1;i<=q;++i)printf("%d\n",ans[i]); 45 }