DTOJ #2402. 任性(willful)

时间:2019-08-06
本文章向大家介绍DTOJ #2402. 任性(willful),主要包括DTOJ #2402. 任性(willful)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

【题目描述】

俗话说,有钱就是任性。我们的高富帅鱼丸同学打算去看电影。鱼丸到了电影院以后,发现座位的编号正好是 $1$ 到 $200$ 。但是有一些座位号对应的座位坏掉了,没法坐,不妨假设还剩下 $N$ 个能坐的椅子。电影的老板告诉鱼丸,如果你要包下一个集合 $S$ 里的所有椅子,就要付出这些椅子的编号的最小公倍数的钱。鱼丸很任性地同意了。

来这里玩了很多天以后,鱼丸发现自己正好来了 $2^N-1$ 天,并且由于他非常任性,对于这 $N$ 个椅子的每一种可能的非空子集,他都包下过来看电影。鱼丸大少爷虽然不在乎花了多少钱,但你毕竟是他的助理,于是你想知道鱼丸一共花了多少钱。由于钱的数量实在太大,请对答案 $mod~1e9+7$之后输出。

【输入格式】

第一行输入一个数 $N(1 \le N \le 200) $,表示能做的椅子的数量。

接下来一行 $N$ 个 $1$ 到 $200$ 之间的整数,用空格隔开。

【输出格式】

一行输出答案。

【样例】

样例输入
2
2 4

样例输出
10

【数据范围与提示】

对于 $20\%$ 的数据,有 $N \le 20$。

对于 $100\%$ 的数据,有 $N \le 200$。

【题解】

又是一道神仙题。。。连个暴力都很难想啊。。。

先考虑 $20$ 分暴力。显然可以枚举子集然后又不会了。最朴素的想法是直接算 $lcm$,结果发现这东西爆 $long long$ 了。。。还没办法边算边取模。。。

于是就是常见的套路:猜性质!这能有啥性质啊根据 $lcm(a,b)=\frac{a \times b}{gcd(a,b)}$,猜想 $lcm(a,b,c)=\frac{a \times b \times c}{gcd(a,b,c)}$,于是我们得到了一个错误的结果。

根据 $lcm$ 的另一个套路,考虑分解质因数。由于 $200$ 以内的质数只有 $46$ 个,把每个数对应的质数个数记下来就好了。

考虑优化。根据另一个常见的性质,最多只有一个大于 $\sqrt n$ 的质数。

又 $\sqrt {200}=14.142135623730950488016887242097...<15$,而 $15$ 以内的质数只有 $6$ 个:$2,3,5,7,11,13$,而每个质数的次数分别不超过 $7,4,3,2,2,2$,可以考虑把这些小质因数的次数记下来 $dp$。

考虑分组,对于剩下的大质数相同的数,放在一起进行转移即可。每组内转移时需要记录当前大质数是否用过,用一个 $0/1$ 表示,而组与组间的大质数显然互不影响,因此每组 $dp$ 完后直接放到下一组的初始化内即可。

【代码】

#include<bits/stdc++.h>
const int mod=1000000007;
const int pr[]={1,2,3,5,7,11,13};
inline int read ( void )
{
	int x=0;char ch;bool f=true;
	while ( !isdigit(ch=getchar()) ) if ( ch=='-' ) f=false;
	for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
	return f ? x : -x ;
}
#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 h=0;h<3;h++)
#define F(i) f[i][a][b][c][d][e][h]
#define G(i,j) g[i][a][b][c][d][e][h][j]
#define H(i,j) g[i][std::max(a,p[i].cnt[1])][std::max(b,p[i].cnt[2])][std::max(c,p[i].cnt[3])][std::max(d,p[i].cnt[4])][std::max(e,p[i].cnt[5])][std::max(h,p[i].cnt[6])][j]
struct Int { int cnt[8],prime; } p[210];
int f[210][8][5][4][3][3][3],g[210][8][5][4][3][3][3][2],ans,n;
inline void Add ( int &x,int y ) { x+=y;x-=(x>=mod)?mod:0; }
inline int power ( int x,int y )
{
	int res=1;
	for ( ;y;x*=x,y>>=1 ) if ( y&1 ) res*=x;
	return res;
}
inline long long calc ( int a,int b,int c,int d,int e,int h,int i )
{
	int res=1;
	if ( p[i].cnt[1]>a ) res*=power(2,p[i].cnt[1]-a);
	if ( p[i].cnt[2]>b ) res*=power(3,p[i].cnt[2]-b);
	if ( p[i].cnt[3]>c ) res*=power(5,p[i].cnt[3]-c);
	if ( p[i].cnt[4]>d ) res*=power(7,p[i].cnt[4]-d);
	if ( p[i].cnt[5]>e ) res*=power(11,p[i].cnt[5]-e);
	if ( p[i].cnt[6]>h ) res*=power(13,p[i].cnt[6]-h);
	return res;
}
signed main()
{
	n=read();
	for ( int i=1;i<=n;i++ )
	{
		int x=read();
		for ( int j=1;j<=6;j++ ) while ( !(x%pr[j]) ) p[i].cnt[j]++,x/=pr[j];
		p[i].prime=x;
	}
	std::sort(p+1,p+n+1,[&](const Int &a,const Int &b){return a.prime<b.prime;});
	f[0][0][0][0][0][0][0]=1;
	for ( int i=1;i<=n;i++ )
	{
		if ( p[i].prime!=p[i-1].prime ) FOR G(i-1,0)=F(i-1),G(i-1,1)=0;
		FOR Add(G(i,0),G(i-1,0)),Add(G(i,1),G(i-1,1)),Add(H(i,1),1LL*G(i-1,0)*p[i].prime%mod*calc(a,b,c,d,e,h,i)%mod),Add(H(i,1),1LL*G(i-1,1)*calc(a,b,c,d,e,h,i)%mod);
		if ( p[i].prime!=p[i+1].prime ) FOR Add(F(i),G(i,0)),Add(F(i),G(i,1));
	}
	FOR Add(ans,F(n));Add(ans,mod-1);
	return !printf("%d\n",ans);
}

  

原文地址:https://www.cnblogs.com/RenSheYu/p/11311675.html