「題解」:$Six$

問題 A: Six

時間限制: 1 Sec  內存限制: 512 MBnode

題面


題面謝絕公開。c++

題解


來寫一篇正經的題解。ide

每個數對於答案的貢獻與數自己無關,只與它包含了哪幾個質因數有關。spa

因此考慮二進制記錄狀態,記憶化搜索。blog

能夠發現,每一個數對於答案的貢獻與其數值自己無關,只與其所包含的素數集合有關。內存

舉個例子:$6(2^1*3^1),12(2^2*3^1),24(2^3*3^1)$在二進制下能夠壓成同一個狀態,由於他們都只包含{2,3}這個素數集合。get

考慮題意所述:新加入的值知足至多與一個已經加入的值不互質。it

換一種理解:新加入的值只要與其中兩及以上個值不互質就不是合法狀態。class

因此考慮對這些素數兩兩配對,記錄數對的出現狀態。因此壓成$2^{21}$個狀態,每一個狀態表明一個數對。(爲何是$21$??$21=C_6^2+6$)搜索

沒有理解?舉個例子:對於樣例,$n=6$,有一種不合法的狀態爲:${2,3,6}$,當咱們加入$6$的時候,它自己包含一個數對${2,3}$,而$2$在已選集合中出現過,$3$在已選集合中某個與$2$出現位置不一樣的位置出現過,則已選集合在數對${2,3}$對應的二進制下爲$1$,此時再加入$6$就不合法了。

總的來說,咱們把$n$的每個約數都視爲一個素數集合,若是當前加入的這個元素有兩個或兩個以上的素數對在已選集合中的兩個及以上集合出現過,則狀態不合法。

根據這樣來壓位存儲狀態,記憶化搜索一發就完了。

具體實現主要難度在預處理??

代碼:

#include<bits/stdc++.h>
#define int long long
#define rint register int
using namespace std;
const int mod=1000000007;
inline void read(int &a)
{
	a=0;int b=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+ch-'0';ch=getchar();}
	a=a*b;return ;
}
int n,sum[1<<6|1],prime[100005],t[7],yxs[100005],cnt[1<<6|1];
int pd[7][7],tag[1<<21|1];
struct node{int x,y;};
bool operator < (node A,node B){
	return (A.x==B.x)?A.y<B.y:A.x<B.x;
}
map <node,int> mp;
inline void devide1()
{
	int lin=n;
	for(rint i=2;i<=sqrt(n);++i)
	{
		if(lin%i==0)
		{
			prime[++prime[0]]=i;
			t[prime[0]]=1<<(prime[0]-1);
			while(lin%i==0)lin/=i;
		}
	}
	if(lin!=1)
	{
		prime[++prime[0]]=lin;
		t[prime[0]]=1<<(prime[0]-1);
	}
	return ;
}
inline void devide2()
{
	for(rint i=1;i<=sqrt(n);++i)
	{
		if(n%i==0)
		{
			if(i!=1)yxs[++yxs[0]]=i;
			if(n/i!=i)yxs[++yxs[0]]=n/i;
		}
	}
	return ;
}
inline void devide3()
{
	for(rint i=1,res;i<=yxs[0];++i)
	{
		res=0;
		for(rint j=1;j<=prime[0];++j)
			if(yxs[i]%prime[j]==0)res|=t[j];
		cnt[res]++;
	}
	return ;
}
inline void start()
{
	devide1();//cout<<1<<endl;
	devide2();//cout<<2<<endl;
	devide3();//cout<<3<<endl;
	pd[1][1]=1<<0,pd[2][2]=1<<1,pd[3][3]=1<<2;
	pd[4][4]=1<<3,pd[5][5]=1<<4,pd[6][6]=1<<5;
	pd[1][2]=pd[2][1]=1<<6;pd[1][3]=pd[3][1]=1<<7;
	pd[1][4]=pd[4][1]=1<<8;pd[1][5]=pd[5][1]=1<<9;
	pd[1][6]=pd[6][1]=1<<10;pd[2][3]=pd[3][2]=1<<11;
	pd[2][4]=pd[4][2]=1<<12;pd[2][5]=pd[5][2]=1<<13;
	pd[2][6]=pd[6][2]=1<<14;pd[3][4]=pd[4][3]=1<<15;
	pd[3][5]=pd[5][3]=1<<16;pd[3][6]=pd[6][3]=1<<17;
	pd[4][5]=pd[5][4]=1<<18;pd[4][6]=pd[6][4]=1<<19;
	pd[5][6]=pd[6][5]=1<<20;
	vector <int> v;
	for(rint i=1;i<=(1<<prime[0])-1;++i)
	{
		v.clear();int res=i;
		for(rint j=1;j<=prime[0];++j)
			if(res&t[j])v.push_back(j);
		for(rint j=0;j<v.size();++j)
			for(rint k=j;k<v.size();++k)
				tag[i]|=pd[v[j]][v[k]];
	}
}
inline int dfs(int us,int ng)
{
	node lode=(node){us,ng};
	if(mp[lode])return mp[lode]%mod;
	for(rint i=1;i<=(1<<prime[0])-1;++i)
	{
		if(tag[i]&ng)continue;
		int lin=ng;
		for(rint j=1;j<=prime[0];++j)
		{
			if(!(i&t[j]))continue;
			for(rint k=1;k<=prime[0];++k)
			{
				if(!(us&t[k]))continue;
				lin|=pd[j][k];
			}
		}
		mp[lode]=(mp[lode]+cnt[i]*(dfs(us|i,lin)%mod+1))%mod;
	}
	return mp[lode]%mod;
}
signed main()
{
	read(n);start();
	printf("%lld\n",dfs(0,0));
	return 0;
}
相關文章
相關標籤/搜索