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

 

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

 

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

 

posted @ 2020-05-05 17:48  DeepinC  阅读(300)  评论(0编辑  收藏  举报