题解:P16141 集合(set)
简单无脑做法!
套路地,以
然后把所有数按照其至多有一个的大质因数分组,因子里有第
我们要计算这个形似
把小质数是否出现状压到集合
设
设
大力转移。对于
那么,对于第
时间复杂度
:::info[代码]
代码实现是直接以
#include<bits/stdc++.h>
#define i128 __int128
#define ll long long
#define ull unsigned long long
#define db double
#define ldb long double
#define Pii pair<int,int>
#define fi first
#define se second
#define f(x,y) fixed<<setprecision(y)<<x
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,rp,stdin),p1==p2)?EOF:*p1++)
using namespace std;
const int N=2e3+10;
const int M=1<<14;
const int mod=998244353;
const int rp=1e6+10;
int n,sq,cnt,res,b[N],pr[N],p[N],dp[N];
int dpl[N][M],dpr[N][M],ans[M];
vector<int> vt[N];
bitset<N> isp;
char buf[rp],*p1=buf,*p2=buf;
inline int read()
{
int x=0,f=1; char c=0;
while(!isdigit(c)) {if(c=='-') f=-1; c=gc();}
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=gc();
return x*f;
}
inline char read_ch()
{
char c=0;
while((!isalpha(c))&&(!isdigit(c))) c=gc();
return c;
}
inline void shai(int n)//埃氏筛
{
isp.set(); isp[0]=isp[1]=0;
for(int i=2;i<=n;++i)
if(isp[i])
{
pr[++cnt]=i; b[i]=cnt;
for(int j=i+i;j<=n;j+=i) isp[j]=0;
}
}
inline void fwt_or(int A[],int v)
{
for(int i=1;i<M;i<<=1)
for(int j=0;j<M;j+=i+i)
for(int k=j;k<i+j;++k)
A[i+k]=(A[i+k]+1ll*A[k]*v)%mod;
}
inline void add(int &x,ll y) {x=(x+y)%mod;}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
cin>>n; shai(2003); sq=14;
for(int i=1;i<=n;++i) if(b[i]) b[i]-=sq; cnt-=sq;//从质数 cnt 变成大质数 cnt
for(int i=1;i<=n;++i)
{
int nw=i;
for(int j=1;j<=sq;++j)
if(!(i%pr[j]))//分解质因数
{
p[i]|=1<<(j-1);
while(!(nw%pr[j])) nw/=pr[j];
}
vt[b[nw]].push_back(i);//按剩下的大质数分组
}
dpl[0][0]=1;//初始化
for(int i=0;i<=cnt;++i)
{
if(i) memcpy(dpl[i],dpl[i-1],sizeof dpl[i]);//注意判 i=0
for(auto a:vt[i])
for(int j=(1<<sq)-1;j>=0;--j)
add(dpl[i][j|p[a]],dpl[i][j]);//倒着,选了 a 的转移
if(i)//这个也是,注意判 i=0
for(int j=0;j<(1<<sq);++j)
add(dpl[i][j],-dpl[i-1][j]);
}
dpr[cnt+1][0]=1;//初始化
for(int i=cnt;i>=0;--i)
{
memcpy(dpr[i],dpr[i+1],sizeof dpr[i]);
for(auto a:vt[i])
for(int j=(1<<sq)-1;j>=0;--j)
add(dpr[i][j|p[a]],dpr[i][j]);//倒着,选了 a 的转移
}
for(int i=0;i<=cnt+1;++i) fwt_or(dpl[i],1),fwt_or(dpr[i],1);//fwt 过去
for(int i=1;i<=cnt;++i)
{
for(int j=0;j<(1<<sq);++j)
ans[j]=1ll*dpl[i-1][j]*dpr[i+1][j]%mod;
fwt_or(ans,-1);//fwt 回来
add(res,1ll*ans[(1<<sq)-1]*pr[i+sq]);//对大质数算贡献
}
for(int i=0;i<(1<<sq);++i)
ans[i]=1ll*dpl[0][i]*dpr[1][i]%mod;
fwt_or(ans,-1);//fwt 回来
for(int i=0;i<(1<<sq);++i)
for(int j=1;j<=sq;++j)
if(!(i&(1<<(j-1))))
{add(res,1ll*ans[i]*pr[j]); break;}//对小质数算贡献
cout<<(res+mod)%mod;
return 0;
}
:::