dtoj2402. 任性(willful)
俗话说,有钱就是任性。我们的高富帅鱼丸同学打算去看电影。鱼丸到了电影院以后,发现座位的编号正好是 $1$ 到 $200$ 。但是有一些座位号对应的座位坏掉了,没法坐,不妨假设还剩下 $N$ 个能坐的椅子。电影的老板告诉鱼丸,如果你要包下一个集合 $S$ 里的所有椅子,就要付出这些椅子的编号的最小公倍数的钱。鱼丸很任性地同意了。
来这里玩了很多天以后,鱼丸发现自己正好来了 $2^N-1$ 天,并且由于他非常任性,对于这 $N$ 个椅子的每一种可能的非空子集,他都包下过来看电影。鱼丸大少爷虽然不在乎花了多少钱,但你毕竟是他的助理,于是你想知道鱼丸一共花了多少钱。由于钱的数量实在太大,请对答案 $mod~1e9+7$之后输出
Sol.
本题 $ N \leq 200 $。
lcm中指数大于1的只能是2,3,5,7,11,13.
令f[i][a][b][c][d][e][f]表示前i个数,他们的指数是a,b,c,d,e,f的答案;
转移时只要看这个数加不加入就行。
那我们还得加上那些其他的质数。
我们考虑把那个大质数拉出来排序。
每次处理含有相同大质数的数。
那么在f后面多一维[0/1]表示当前处理的大指数是否出现过即可。
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define For for(int a=0;a<8;a++)for(int b=0;b<5;b++)for(int c=0;c<4;c++)for(int d=0;d<3;d++)for(int e=0;e<3;e++)for(int f=0;f<3;f++) #define S [a][b][c][d][e][f] #define ns [max(a,s[i].t[0])][max(b,s[i].t[1])][max(c,s[i].t[2])][max(d,s[i].t[3])][max(e,s[i].t[4])][max(f,s[i].t[5])] #define mod 1000000007 #define ll long long using namespace std; int n,p[6]={2,3,5,7,11,13},ans; ll g[202][8][5][4][3][3][3][2],dp[8][5][4][3][3][3]; struct node{ int M,t[6]; }s[202]; bool cmp(node A,node B){return A.M<B.M;} int w(int a,int num){ if(num<=0)return 1; int A=1;for(;num;num>>=1,a=a*a%mod)if(num&1)A=A*a;return A; } int calc(int i,int a,int b,int c,int d,int e,int f){ return w(p[0],s[i].t[0]-a)*w(p[1],s[i].t[1]-b)*w(p[2],s[i].t[2]-c)*w(p[3],s[i].t[3]-d)*w(p[4],s[i].t[4]-e)*w(p[5],s[i].t[5]-f); } int main(){ cin>>n; for(int i=1,v;i<=n;i++){ scanf("%d",&v); for(int j=0;j<6;j++)while(v%p[j]==0)v/=p[j],s[i].t[j]++; s[i].M=v; } sort(s+1,s+n+1,cmp); dp[0][0][0][0][0][0]=1; for(int i=1;i<=n;i++){ if(s[i].M!=s[i-1].M)For g[i-1]S[0]=dp S,g[i-1]S[1]=0; For g[i]S[0]=g[i-1]S[0],g[i]S[1]=g[i-1]S[1]; For{ (g[i]ns[1]+=g[i-1]S[0]*s[i].M%mod*calc(i,a,b,c,d,e,f)%mod)%=mod; if(s[i].M==s[i-1].M)(g[i]ns[1]+=g[i-1]S[1]*calc(i,a,b,c,d,e,f))%=mod; } if(s[i].M!=s[i+1].M)For dp S= (g[i]S[0]+g[i]S[1])%mod; } For (ans+=dp S)%=mod; cout<<ans-1<<endl; return 0; }