首页 > 其他分享 >P8292 [省选联考 2022] 卡牌

P8292 [省选联考 2022] 卡牌

时间:2023-02-20 23:11:08浏览次数:47  
标签:P8292 ll 2003 省选 质数 ret int 联考 mod

我决定不整什么写过的题的集合了,写不过来。

想到啥题好就写啥。

这题是个很好的套路。

考虑到值域不怎么大,想到根号分治。也就是小于根号的质数不超过 \(14\) 个,大于根号的质数只有一个。

考虑寿司晚宴的做法,对小质数和大质数分开做。如果是小质数,那么 \(14\) 个可以状态压缩。然后考虑容斥,直接找全包括肯定不好做,考虑做一个都没有的。

\(ans=\sum\limits_{S\in target} (-1)^{|S|} f_{S}\),\(f_S\) 表示这个状态下每个数字都包括这个状态,选择数字的方案数。

然后考虑怎样做大质数的。就是统计下每个 \(S\) 下不同的大质数的个数,假设当前询问包大质数 \(g\),当前的状态包含这个数字的数量为 \(cnt\),那么这个状态下的 \(f\) 就要乘 \(2^{cnt}-1\),因为至少要选一个,反之,如果询问不包含这个 \(g\),那么方案数乘 \(2^{cnt}\)。

然后就能求出带大质数时的 \(f_S\)。然后正常容斥一下就行。

我是把一个大质数都不算的设为 \(1\)。

然后被卡常了,可以预处理一些 \(2^k\) 之类的。

我说的不清楚喵,看代码喵。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2003;
const int mod=998244353;
ll ksm(ll x,ll y)
{
	ll ret=1;
	while(y)
	{
		if(y&1) ret=ret*x%mod;
		x=x*x%mod; y>>=1; 
	}
	return ret;
}
int n,m;
int s[1000052];
int prime[maxn],cnt_tot;bool vis[maxn];
int f[9002][2003];ll val[9005],ss[9002][2003],inv[9002][2003]; vector<int> que;
int mp[3002],pos[2003],q[2003],lst[maxn],a[maxn];
bitset<5> S;int B=8191;
void init()
{
	for(int i=2;i<=2000;i++)
	{
		if(vis[i]) continue;
		cnt_tot++; prime[cnt_tot]=i; pos[i]=cnt_tot;
		for(int j=i+i;j<=2000;j+=i) vis[j]=1; 
	}
	for(int i=1;i<=2000;i++)
	{
		lst[i]=1;
		for(int j=1;j<=cnt_tot;j++) 
		{
			if(i%prime[j]) continue;
			if(j<=13) q[i]|=(1<<(j-1));
			else lst[i]=j;
		}
		//S=q[i]; cout<<i<<"  "<<S<<endl;
	}
	for(int i=0;i<(1<<13);i++) 
	{
		for(int j=1;j<=2000;j++) 
		{
			if(((B^q[j])&i)!=i) continue;
			f[i][lst[j]]=(f[i][lst[j]]+a[j])%mod;
		}
	}
	for(int i=0;i<(1<<13);i++)
	{
		val[i]=1ll;
		for(int j=1;j<=cnt_tot;j++)
		{
			if(j>=2&&j<=13) continue;
			val[i]=val[i]*ksm(2,f[i][j])%mod;
			ss[i][j]=ksm(2,f[i][j]);
			inv[i][j]=ksm(ss[i][j],mod-2);
		}
	}
	/*for(int i=0;i<(1<<4);i++) 
	{
		for(int j=1;j<=2000;j++) 
		{
			if(f[i][j])
			{
				S=i; cout<<"f["<<S<<"]["<<j<<"]="<<f[i][j]<<endl;
			}
		}
	}*/
}
namespace IO
{
	#define gc()(xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<20,stdin),xS==xTT)?0:*xS++)
	#define pc(x)(p3-obuf<1000000)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
	char xch,xB[1<<20],*xS=xB,*xTT=xB,obuf[1000000],*p3=obuf;
	inline ll read(){char ch=gc();ll x=0,f=1;while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}while('0'<=ch&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}return x*f;}
	static char cc[20];template<typename item>
	inline void pt( item x){ int len=0;if(!x)pc('0');if(x<0)x=-x,pc('-');while(x)cc[len++]=x%10+'0',x/=10;while(len--)pc(cc[len]);}
	inline void pS(string s){for(int i=0;i<s.length();i++)pc(s[i]);}
	inline ll read2(){char ch=gc();ll x=0,f=1;while(ch<'0'||ch>'1'){if(ch=='-')f=-1;ch=gc();}while('0'<=ch&&ch<='9'){x=(x<<1)+(ch^48);ch=gc();}return x*f;}
}
vector<int> big; 
int main()
{
	//freopen("card.in","r",stdin);
	//freopen("card.out","w",stdout);
	n=IO::read();
	for(int i=1;i<=n;i++) s[i]=IO::read(),a[s[i]]++;
	m=IO::read();
	init();
	while(m--)
	{
		int c,tmp; big.resize(0); que.resize(0); 
		c=IO::read();
		for(int i=0;i<=2000;i++) mp[i]=0;
		int bak=0; 
		for(int i=1;i<=c;i++) 
		{
			tmp=IO::read();que.push_back(tmp),mp[tmp]=1;
			if(pos[tmp]<=13) bak|=(1<<(pos[tmp]-1));
			else big.push_back(pos[tmp]);
		}
		ll ans=0;
		for(int i=bak;i>=0;i=bak&(i-1)) 
		{
			ll ret=val[i];
			for(auto j:big) 
			{
				ret=ret*(ss[i][j]-1)%mod*inv[i][j]%mod;
			}
			if(!i)
			{
				ans=(ans+ret)%mod;
				//S=i; cout<<S<<"  "<<ret<<endl;
				break;
			}
			else
			{
				int cnt=__builtin_popcount((i&bak));
				if(cnt&1) ans=(ans-ret+mod)%mod;
				else ans=(ans+ret)%mod;
				//S=i; cout<<S<<"  "<<ret*((cnt&1)?-1:1)<<endl;
			}
		}
		printf("%lld\n",ans);
	}
	fprintf(stderr,"%.4lf\n",1.0*clock()/CLOCKS_PER_SEC);
}

标签:P8292,ll,2003,省选,质数,ret,int,联考,mod
From: https://www.cnblogs.com/cc0000/p/17139351.html

相关文章

  • [省选联考 2022] 填树 题解
    神奇dp。发现我看到dp大多数时候只会暴力。那我约等于退役了啊。题意:自己看。首先有一个显然的暴力。枚举一个最小值\(L\),然后区间就限定在了\([L,L+K]\)。那么普及......
  • 省选联测32
    nnd考不动了,脑子不转了已经A.光明正解做法是\(O(n)\)的,长剖一下,在链上差分贡献,但是貌似常数极大,不知道为啥开六秒。赛时写的是两个log的二分加启发式,实际表现和\(O(n)\)......
  • 「考试总结」2023-02-13 联合省选模拟赛 – Day1
    爆搜$\texttt{(dfs)}$$\texttt{Statement}$给定一个$n$个点$m$条边的简单无向图,你需要对所有匹配$S$,把$c^{|S|}$求和,其中$|S|$是匹配......
  • 省选联测31
    A.西克赛时冲了四个小时,在下行部分假了无数个做法。暴力两个log的话就倍增走一条重链,然后切重链,来回操作就行了。题解点击查看代码//ubsan:undefined//accod......
  • 「解题报告」[省选联考 2021 A/B 卷] 图函数
    我不会最短路了?显然每对点能对答案造成的贡献是一个前缀,考虑求出每对点能造成贡献的最大时间。首先能发现,如果\(v>v'\),那么假如\(v\tov'\tou\),那么\(v'\tou\)......
  • 「解题报告」[省选联考 2021 A 卷] 矩阵游戏
    啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会......
  • P3750 [六省联考 2017] 分手是祝愿
    \(\mathcalLink\)考虑建立异或方程组,则最终状态为该方程组的一个解,第\(i\)个方程形如\(\displaystyle\bigoplus_{i\midd}x_d=a_i\)。这些方程构成的向量线性无关,......
  • 省选联测27
    A.神奇纸牌比较好像的题,考虑一个数字一个数字的加,这样就变成了n个点,每个点四个01属性,有相同1属性就相连,最后是个连通图就行。点击查看代码//ubsan:undefined//acco......
  • 省选模拟28
    说句闲话学了会儿头插dp,转移是这样写的,\(Chen\_jr\)锐评:插头你还短路,你不烧谁烧于是脑子烧坏了来补题解(!is_d)&&(!is_r)&&mp[i+1][j]&mp[i][j+1]//needtomake......
  • 「解题报告」[省选联考 2022] 序列变换
    我不是很能理解?神奇贪心题。括号序列考虑直接整树形结构,然后操作就是将一个子树内所有儿子放到另一颗子树里,并把这个点单独放到这个子树内,贡献为\(x\)乘终点子树权值加......