您的位置:首页 > 其它

计蒜客 15971 腾讯消消乐 题解

2017-06-22 18:26 169 查看

题意

腾讯推出了一款益智类游戏——消消乐。游戏一开始,给定一个长度为 n 的序列,其中第 i 个数为 A​i。

游戏的目标是把这些数全都删去,每次删除的操作为:选取一段连续的区间,不妨记为 [L,R],如果这一段区间内所有数的最大公约数≥k(k 值在游戏的一开始会给定),那么这一段区间就能被直接删去。

注意:一次删除以后,剩下的数会合并成为一个连续区间。

定义 f(i) 为进行 i 次操作将整个序列删完的方案数。

你需要实现一个程序,计算 ∑ni=1(f(i)∗i) mod 1000000007。

思路

状态压缩dp,对于每一个状态,记录到达这一状态需要i次操作的方案数,然后转移至下一状态,最后得到结果

代码

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define mod 1000000007
long long a[20];
long long ans[(1<<18)][20];
long long now[20];
long long anss;
long long n,K,e,ii,temp,g;
long long gcd(long long a,long long b)
{
if(a%b==0)
return b;
else if(b%a==0)
return a;
else if(a>b)
return gcd(b,a%b);
else return gcd(a,b%a);
}
int main()
{
scanf("%lld%lld",&n,&K);
for(long long i=0;i<n;i++)
scanf("%lld",&a[i]);
e=(1LL)<<n;
ans[0][0]=1;
for(long long i=0;i<e;i++)
{
ii=i;
for(long long j=0;j<n;j++)
{
now[n-1-j]=ii%2;
ii>>=1;
}
for(long long j=0;j<n;j++)
{
if(now[j])
continue;
temp=0;
g=a[j];
for(long long k=j;k<n;k++)
{
if(now[k])
continue;
g=gcd(g,a[k]);
if(g>=K)
{
temp|=(1LL<<(n-1-k));
for(long long p=1;p<=n;p++)
ans[i|temp][p]+=ans[i][p-1];
}
else break;
}
}
}
anss=0;
for(long long i=1;i<=n;i++)
anss=(anss+((ans[e-1][i]%mod)*i)%mod)%mod;
printf("%lld\n",anss);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: