9.28 csp-s模拟测试54 x+y+z
Posted jrf123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.28 csp-s模拟测试54 x+y+z相关的知识,希望对你有一定的参考价值。
T1 x
求出每个数的质因数,并查集维护因子相同的数,最后看一共有多少个联通块,$ans=2^cnt-2$
但是直接分解会$T$,埃筛是个很好的选择,或者利用每个数最多只会有1个大于$\sqrtn$的质因子,线筛$1e6$内的素数,每次只需枚举$1e3$的质因数就行,复杂度也可以过去
#include<iostream> #include<cstdio> #include<bitset> #include<cmath> #include<cstring> #include<vector> #define ll long long #define mod 1000000007 using namespace std; ll T,n,ans,a[100100],prime[100100],fa[100100],num,pr[1001000],tot; bitset<100100>vis; bitset<1001000>v; vector<int>ve[1001000]; ll read() ll aa=0,bb=1;char cc=getchar(); while(cc>‘9‘||cc<‘0‘)if(cc==‘-‘) bb=-1;cc=getchar(); while(cc>=‘0‘&&cc<=‘9‘)aa=(aa<<3)+(aa<<1)+(cc^‘0‘);cc=getchar(); return aa*bb; ll quick(ll x,ll p) ll as=1; while(p) if(p&1) as=as*x%mod; x=x*x%mod; p>>=1; return as; ll find(ll x) if(x!=fa[x]) fa[x]=find(fa[x]); return fa[x]; void init() for(int i=2;i<=1000000;i++) if(v[i]) continue;prime[++tot]=i; for(int j=i;j<=1000000;j+=i) v[j]=1; ve[j].push_back(i); int main() T=read();init(); while(T--) n=read();ans=0;num=0;vis.reset();memset(pr,0,sizeof(pr)); for(int i=1;i<=n;i++) a[i]=read(),fa[i]=i; for(int i=1;i<=n;i++) for(int j=0;j<ve[a[i]].size();j++) if(pr[ve[a[i]][j]]) fa[find(i)]=find(pr[ve[a[i]][j]]); else pr[ve[a[i]][j]]=i; for(int i=1;i<=n;i++) int f=find(i); if(!vis[f]) vis[f]=1,num++; ans=(quick(2,num)-2+mod)%mod; printf("%lld\n",ans); return 0;
T2 y
$bitset$的灵活应用
一开始的思路是$2^20$枚举状态,记忆化搜索,$f[i][sta]$表示从i点出发能否走出$sta$的状态(状态的第一位表示长度),但是空间开不下,时间也扛不住
所以改变策略,只记录一半的状态,最后枚举中间点
$f[i][sta][j]$表示起点为$i$,终点为$j$,中间为状态$sta$是否可行
正常需要枚举一个点,一个状态,然后在枚举一个点,再枚举与第二个点有边相连的点,如果前两个点之间的$sta$状态可行,那么第一个点与第三个点之间$sta<<1|h[i].w$也是可行的
但是,时间显然不优秀
$bitset$就有用了,如果两个点之间的$sta$状态是可行的,那么第一个点与这个状态的终点和第二个点的连边是一样的,所以建边的时候用$bitset$邻接表,再加一维表示是$0$还是$1$,$bitset$合并就行,最后只需要枚举状态和中点,看是否能拼成这个状态
还有就是要在每个状态的第一位表示长度,不然$01$和$001$状态是分不清的。对于$01$串为奇数的要处理好$len/2$与$len/2+1$两个长度的关系
#include<iostream> #include<cstdio> #include<cstring> #include<bitset> using namespace std; int n,m,d,ans; bitset<99>f[99][(1<<12)+5],bt[2][99]; int read() int aa=0,bb=1;char cc=getchar(); while(cc>‘9‘||cc<‘0‘)if(cc==‘-‘) bb=-1;cc=getchar(); while(cc>=‘0‘&&cc<=‘9‘)aa=(aa<<3)+(aa<<1)+(cc^‘0‘);cc=getchar(); return aa*bb; int main() n=read();m=read();d=read();int dd=d/2,dis=d-dd; int u,v,c; for(int i=1;i<=m;i++) u=read();v=read();c=read(); bt[c][u][v]=1;bt[c][v][u]=1; f[u][c|2][v]=1;f[v][c|2][u]=1; for(int i=1;i<=n;i++) for(int sta=2;sta<(1<<(dis+1));sta++) for(int j=1;j<=n;j++) if(!f[i][sta][j]) continue; f[i][sta<<1|1]|=bt[1][j]; f[i][sta<<1|0]|=bt[0][j]; for(int i=0;i<(1<<d);i++) bool flag=0; for(int j=1;j<=n;j++) if(f[1][i>>dd|(1<<dis)][j]&&f[j][i&((1<<dd)-1)|(1<<dd)].count()) flag=1; break; if(!flag&&dd!=dis) for(int j=1;j<=n;j++) if(f[1][i>>dis|(1<<dd)][j]&&f[j][i&((1<<dis)-1)|(1<<dis)].count()) flag=1; break; ans+=flag; printf("%d\n",ans); return 0;
T3 z
咕了
不想退役就应该踏实
以上是关于9.28 csp-s模拟测试54 x+y+z的主要内容,如果未能解决你的问题,请参考以下文章