atcoder2069
Posted pandaking
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了atcoder2069相关的知识,希望对你有一定的参考价值。
链接:https://vjudge.net/contest/308181#problem/H
题意:给了你N个数,和一个数a,让你从这N个数中选择出一些数,并使这些数的sum和是a的倍数。问你有多少种方案数。
dp的通常想法是我们先设计出状态和转移,然后根据状态和转移我们调整得到可以接受的复杂度。。。。。。。。。。
由于这个数字都不大,我们可以设计出一个n^4的做法。这样也就(50^4)的复杂度,也就(2500*2500)差不600w左右。。。。。。。。。。。。。。。。
设置状态为dp[i][j][k].表示我们从前i个数中(第i个数可以选或者不选(这个得搞清楚,选和不选是不同的。。。。。。。))选j个数的合为k的总的方案数。。。。。。。。。
然后转移的话有从当前往后转移,还有从后往前转移。。。。。。。。。。。
然后第一个纬度是可以去掉的,但是我们去掉第一个纬度之后就会出现一中情况,我们转移的时候要变成倒叙。倒序是为什么防止被覆盖。。。。。。
这个也没啥。。。。。。。。
下面是代码:
我个人感觉的dp题目的做法: 1:你首先得知道这是一个dp题或者你能挖掘出某种通过dp来做的做法,比如一些性质和转移方式。
2:然后就是设计状态和转移方式(这是比较关键的一步)
3:接下来就是优化状态和转移方式
4:弄好了这些以后接下来可以就是怎么代码实现。比如倒序实现,初始值处理,最后需要的值,有那些冗余的值是不需要更新的。。。。。。。。。。。。。。
接下来是代码:
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <bitset> 7 typedef long long ll; 8 using namespace std; 9 int n,a; 10 ll dp[52][52][2555]; 11 int num[55]; 12 int main() 13 scanf("%d%d",&n,&a); 14 for(int i=1;i<=n;i++) scanf("%d",&num[i]); 15 dp[1][1][num[1]]=1; 16 dp[1][0][0]=1; 17 //从前1个中选1 或者选0个的都为1 18 //其他没有的都设置成0就行了,也不会参与更新。。。。。。。。。。。。。。。 19 for(int i=2;i<=n;i++) 20 dp[i][1][num[i]]++; 21 //这个只能用++ ,应该还是能懂的 22 for(int j=1;j<=i;j++) 23 for(int k=1;k<=(i*50);k++) 24 dp[i][j][k]+=dp[i-1][j][k]; 25 //表示第i个没选 26 dp[i][j][num[i]+k]+=dp[i-1][j-1][k]; 27 //表示第i个选了 28 //这个应该在转移设计里面就想好的。。。。。。。。 29 30 31 32 33 ll ans=0; 34 for(int i=1;i<=n;i++) 35 ans+=dp[n][i][i*a]; 36 //最后算答案的贡献。。。。。。。 37 38 printf("%lld\n",ans); 39 40 return 0; 41
以上是关于atcoder2069的主要内容,如果未能解决你的问题,请参考以下文章
Donation---AtCoder - AtCoder Regular Contest 098
AtCoder Regular Contest 062 E - AtCoDeerくんと立方体づくり / Building Cubes with AtCoDeer
AtCoder Nuske vs Phantom Thnook AtCoder
AtCoder Regular Contest 092 2D Plane 2N Points AtCoder - 3942 (匈牙利算法)