Luogu2150 寿司晚宴
Description
给定 求将 的所有数分成两份,使得两份中的每一对数都互质的方案数,可以有数不在任何一份中
Solution
不互质就是有共同的因子,但直接状压因为素数个数过多而复杂度无法接受
注意到一个数必然的构成要不是单独是一个质数,要不必然有一个 一下的质因子,即 个素数
计算每个数字大于 的因子并排序,不难发现每个数最多有一个次数为 的较大素因子
下面的 ”段“ 指那些较大质因子相同的数字组成的那个段,每个素数或 自成一个段
具体地来说……设一个 来统计答案, 表示在段内的给第一个人统计的方法, 表示在段内给第二个人统计的方法
在段开始处理的时候把 的值赋给
如果 , 那么这种方案合法
对于段内的每个数字, 计算 它包含的小质数集合,能与的就进行转移
处理完每个段之后要
最后把所有的合法状态一统计即可
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define For(i,a,b) for(int i=a;i<=b;++i)
namespace yspm{
inline int read(){
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=510,SZ=1<<8;
int n,pri[N],cnt,fl[N],f[SZ][SZ],g[SZ][SZ],ans[SZ][SZ],mod;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int del(int x,int y){return x-y<0?x-y+mod:x-y;}
struct node{
int id,val,k;
#define k(i) num[i].k
#define val(i) num[i].val
#define id(i) num[i].id
bool operator <(const node &a)const{return val<a.val;}
}num[N];
inline void calc(int x){
int t=x; id(x)=x;
for(int i=1;i<=min(cnt,8ll);++i){
if(x%pri[i]==0){
while(x%pri[i]==0) x/=pri[i];
k(t)|=1<<(i-1);
}
} if(x>1) val(t)=x; else val(t)=-t; return ;
}
inline void seive(int x){
For(i,2,x){
if(!fl[i]) pri[++cnt]=i;
for(int j=1;j<=cnt&&i*pri[j]<=x;++j){
fl[i*pri[j]]=1; if(i%pri[j]==0) break;
}
} For(i,2,x) calc(i);
return ;
}
inline int find(int x){
int res=x; while(val(res+1)==val(res)) ++res;
return res;
}
int s=0,r;
inline void work(){
For(i,0,s) For(j,0,s) if(!(i&j)) ans[i][j]=del(add(f[i][j],g[i][j]),ans[i][j]);
return ;
}
signed main(){
n=read(); mod=read(); seive(n); s=1;
for(int i=1;i<=cnt;++i) if(pri[i]<=19) s<<=1; else break;
--s; sort(num+2,num+n+1);
ans[0][0]=1;
for(int i=2;i<=n;++i){
r=find(i);
For(j,0,s) For(k,0,s) f[j][k]=ans[j][k],g[j][k]=ans[j][k];
For(j,i,r){
for(int s1=s;s1>=0;--s1){
for(int s2=s;s2>=0;--s2){
if(s1&s2) continue;
if((k(j)&s1)==0) f[s1][s2|k(j)]=add(f[s1][s2|k(j)],f[s1][s2]);
if((k(j)&s2)==0) g[s1|k(j)][s2]=add(g[s1|k(j)][s2],g[s1][s2]);
}
}
} i=r; work();
}
int tot=0;
For(i,0,s) For(j,0,s) if(!(i&j)) tot=add(tot,ans[i][j]);
printf("%lld\n",tot);
return 0;
}
}signed main(){return yspm::main();}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律