hdu5656 CA Loves GCD
来源:互联网 发布:快手后期制作软件名字 编辑:程序博客网 时间:2024/06/02 07:01
题目的意思就是:
n个数,求n个数所有子集的最大公约数之和。
第一种方法:
枚举子集,求每一种子集的gcd之和,n=1000,复杂度O(2^n)。
谁去用?
所以只能优化!
题目中有很重要的一句话!
We guarantee that all numbers in the test are in the range [1,1000].
这句话对解题有什么帮助?
子集的种数有2^n种,但是,无论有多少种子集,它们的最大公约数一定在1-1000之间。
所以,我们只需要统计1-1000的最大公约数中可以有多少中方法凑成就可以了!
我们就会考虑dp。
官方题解:
我们令dp[i][j]表示在前i个数中,选出若干个数使得它们的gcd为j的方案数,于是只需要枚举第i+1个数是否被选中来转移就可以了。令第i+1个数为v,当考虑dp[i][j]的时候,我们令$dp[i+1][j] += dp[i][j],dp[i+1][gcd(j,v)] += dp[i][j]。复杂度O(N*MaxV) MaxV 为出现过的数的最大值。
看代码:
#include<cstdio>#include<cstring>const int mod=1e8+7;const int maxn=1005;typedef long long ll;int a[maxn];ll dp[maxn][maxn];int g[maxn][maxn];int gcd__(int n,int m){ if(m==0)return n; return gcd__(m,n%m);}void scanf_(int&data){ data=0; char ch; while((ch=getchar())&&(ch<'0'||ch>'9')){ } do{ data=data*10+ch-'0'; ch=getchar(); }while(ch>='0'&&ch<='9');}int main(){ int T; for(int i=1;i<=1000;++i){ for(int j=i;j<=1000;++j){ g[j][i]=g[i][j]=gcd__(i,j); } } scanf_(T); while(T--){ int n; scanf_(n); for(int i=0;i<n;++i){ scanf_(a[i]); } memset(dp,0,sizeof(dp)); for(int i=0;i<n;++i){ dp[i][a[i]]++; for(int j=1;j<=1000;j++){ dp[i+1][j]+=dp[i][j]; int v_=a[i+1]; dp[i+1][g[v_][j]]+=dp[i][j]; if(dp[i+1][j]>=mod)dp[i+1][j]%=mod; if(dp[i+1][g[v_][j]]>=mod)dp[i+1][g[v_][j]]%=mod; } } ll ans=0; for(int i=1;i<=1000;++i){ if(!dp[n][i])continue; ans+=((i*dp[n][i])%mod); if(ans>=mod)ans%=mod; } printf("%lld\n",ans); } return 0;}
这里的dp数组是二维的,我们优化为一维。
#include<cstdio>#include<cstring>const int mod=1e8+7;const int maxn=1005;typedef long long ll;int a[maxn];ll dp[maxn];int g[maxn][maxn];int gcd__(int n,int m){ if(m==0)return n; return gcd__(m,n%m);}void scanf_(int&data){ data=0; char ch; while((ch=getchar())&&(ch<'0'||ch>'9')){ } do{ data=data*10+ch-'0'; ch=getchar(); }while(ch>='0'&&ch<='9');}int main(){ int T; for(int i=1;i<=1000;i++){ for(int j=i;j<=1000;j++){ g[j][i]=g[i][j]=gcd__(i,j); } } scanf_(T); while(T--){ int n; scanf_(n); for(int i=0;i<n;i++){ scanf_(a[i]); } memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++){ for(int j=1;j<=1000;j++){ if(!dp[j])continue; int _t=g[a[i]][j]; dp[_t]=(dp[_t]+dp[j]); if(dp[_t]>=mod)dp[_t]%=mod; } dp[a[i]]++; } ll ans=0; for(int i=1;i<=1000;i++){ if(!dp[i])continue; ans+=((i*dp[i])%mod); if(ans>=mod)ans%=mod; } printf("%lld\n",ans); } return 0;}
感觉自己dp还是没怎么接触过,所以十分陌生!
主要还是自己的思维不够,不能转化,种数虽然很大,但是gcd的情况是不会变的,总是在1-1000之间,我们计算每个数的情况就可以了!
这也在提示我们,以后刷题,多换个方向思考!
只需要换个角度考虑问题就行了!
1 0
- hdu5656 CA Loves GCD
- hdu5656 CA Loves GCD
- HDU5656 CA Loves GCD (BC)
- 【HDU5656】CA Loves GCD——动态规划
- 【HDU5656】CA Loves GCD,容斥思想与乱搞
- HDU - CA Loves GCD
- HDU 5656:CA Loves GCD
- HDU 5656 CA Loves GCD
- HDU 5656 CA Loves GCD
- hdu CA Loves GCD dp
- hdu 5656 CA Loves GCD
- HDU 5656 CA Loves GCD
- HDU 5656 CA Loves GCD
- HDU 5656 CA Loves GCD
- BestCoder Round #78 CA Loves GCD
- bc 4.2 1002 CA Loves GCD dp
- 杭电5656 CA Loves GCD
- hdoj 5656 CA Loves GCD 【dp】
- Java实现字符串倒序输出的常用方法小结
- 高速系统中滤波电容的选择
- fzu2127
- notepad++ 编辑GAMS文件
- 【开源】Caffe、TensorFlow、MXnet三个开源库对比
- hdu5656 CA Loves GCD
- mycat 用Jconsole监控mycat压测的各种性能曲线
- 1001. A+B Format
- 2016.4.3社会经济热点
- 递归实现格雷码
- 一个类继承父类后创建时,代码执行逻辑问题
- Android键盘面板冲突 布局闪动处理方案
- Web项目自定义错误页面
- 关于python opencv使用