计蒜客 15971 腾讯消消乐 题解
2017-06-22 18:26
169 查看
题意
腾讯推出了一款益智类游戏——消消乐。游戏一开始,给定一个长度为 n 的序列,其中第 i 个数为 Ai。游戏的目标是把这些数全都删去,每次删除的操作为:选取一段连续的区间,不妨记为 [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; }
相关文章推荐
- 计蒜客 腾讯消消乐
- 计蒜客 2017 复赛 腾讯消消乐 (状压dp)
- 计蒜客-2017 计蒜之道 复赛-F-腾讯消消乐
- 计蒜客 429(腾讯手机地图-pi的精确值)
- 2017 计蒜之道 复赛 腾讯消消乐【状压dp】
- 计蒜客 429(腾讯手机地图-pi的精确值)
- 计蒜客 腾讯狼人杀(困难) 最大权密度子图变种
- 计蒜客 腾讯狼人杀 简单 状压+枚举
- 计蒜客 2017 复赛 腾讯消消乐 状压dp
- (状压dp)2017 计蒜之道 复赛 F. 腾讯消消乐
- 计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 F 腾讯消消乐 状态压缩dp、枚举+剪枝
- 计蒜之道2017F-腾讯消消乐(状压dp)
- 计蒜客 腾讯手机地图
- 2017 计蒜之道 复赛 腾讯消消乐
- 计蒜之道-2017复赛-腾讯消消乐(状压DP)
- 计蒜之道-2017复赛-腾讯消消乐(状压DP)
- 计蒜客 腾讯手机地图(模拟 数学)
- 计蒜之道复赛 腾讯消消乐
- 腾讯消消乐 状压dp加普通dp
- 腾讯:致广大QQ用户的一封信