T1 x
求出每个数的质因数,并查集维护因子相同的数,最后看一共有多少个联通块,$ans=2^{cnt}-2$
但是直接分解会$T$,埃筛是个很好的选择,或者利用每个数最多只会有1个大于$\sqrt{n}$的质因子,线筛$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; }
x
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; }
y
T3 z
咕了
不想退役就应该踏实
原文地址:https://www.cnblogs.com/jrf123/p/11611362.html
时间: 2024-10-01 09:22:32