LOJ6356 四色灯

传送门

子任务1:m=1

直接算两遍选或不选就可以了

期望得分:10

子任务2:n<=1e4 m<=5

两种方法

一。枚举每一个数,看它被几个数整除,它对答案有贡献当且仅当被选4k次(k∈N)所以一个数的贡献就是\sum \binom{x}{4k}*2^{m-x}

时间复杂度:O(nm)

二。枚举m的子集,因为m<=5可以进行类似求n个数里不被某几个数整除的数的个数一样的容斥,只需要把4的容斥系数改成2就可以了。时间复杂度:O(3^m*m)

期望得分:30

子任务3:n<=1e9 m<=20

首先我们根据子任务二中枚举m的子集的方法拓展一下。

令f(s)表示[1,n]中多少数是s集合中的数的公倍数

f(s)=\frac{n}{lcm_{x \epsilon s} x}

g(s)表示[1,n]中恰好被s整除但不会被除s的子集外整除的数的个数

g(s)=g(x)*(-1)^{|s|-|x|} ({x \epsilon s})可以通过枚举子集来进行转移 时间复杂度O(3^n)

我们接下来开始优化

令F(i)表示\sum_{|s|=i} f(s) G(i)同理

G(i)=F(i)-\sum_{j=i+1}^m \binom{j}{i}G(j)这个可以理解成因为对于j>i所以j一定包含了C(j,i)个大小为i的子集所以我们把它减掉就可以了

G(i)=\sum _{j=i}^{n} (-1)^{j-i}\binom{j}{i}F(j)这个其实就是把上面的G(j)改成以F的容斥所以长的差不多qwq

很明显F可以在O(2^m*m)的时间复杂度内计算完

G可以在O(m^2)的时间复杂度容斥

所以总复杂度为O(2^m*m)

期望得分100

附代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define mdn 998244353
#define mod(x) (x>=mdn?x-mdn:x)
using namespace std;

int m,a[23],n;
int G[23],f[23][23];
int gcd(int x,int y)
{
	return y==0?x:gcd(y,x%y);
}
int count(int x)
{
	int cnt=0;
	while(x)
	{
		if(x&1)	cnt++;
		x>>=1;
	}
	return cnt;
}
void pre()
{
	f[0][0]=f[1][0]=f[1][1]=1;
	for(int i=2;i<=m;i++)
	{
		f[i][i]=f[i][0]=1;
		for(int j=1;j<i;j++)
			f[i][j]=mod(f[i-1][j]+f[i-1][j-1]);
	}
}
int C(int x,int y)
{
	return f[x][y];
}
int ksm(int bs,int mi)
{
	int ans=1;
	while(mi)
	{
		if(mi&1)	ans=(ll)ans*bs%mdn;
		bs=(ll)bs*bs%mdn;mi>>=1;
	}
	return ans;
}
int main()
{
	int ans=0;
	scanf("%d%d",&n,&m);pre();
	for(int i=1;i<=m;i++)	scanf("%d",&a[i]);
	for(int i=1;i<(1<<m);i++)
	{
		int g=1,f,j,cnt=count(i);
		for(j=0;j<m;j++)
		{
			if(i&(1<<j))
			{
				f=gcd(a[j+1],g);
				if((ll)g/f*a[j+1]>n)	break;
				g=g/f*a[j+1];
			}
		}
		if(j<m)	continue;
		else	G[cnt]=mod(G[cnt]+n/g);
	}
	G[0]=n;
	for(int i=m;~i;i--)
		for(int j=i+1;j<=m;j++)
			G[i]=mod(G[i]-(ll)G[j]*C(j,i)%mdn+mdn);
	//for(int i=0;i<=m;i++)	printf("%d\n",G[i]);
	for(int i=0;i<=m;i++)
		for(int j=0;j<=i;j+=4)
			ans=mod(ans+(ll)G[i]*C(i,j)%mdn*(1<<m-i)%mdn);
	printf("%d\n",(ll)ans*ksm((1<<m),mdn-2)%mdn);
	return 0;
}

 

posted @ 2018-11-28 10:21  寒雨微凝  阅读(221)  评论(0编辑  收藏  举报