牛客2020跨年场 B-牛牛想起飞 dp
中文题面就直接复制了
给定一个长度为 n 的序列a和一个长度为 n 的序列b,对于序列a中的每一个数字$a_i$,牛牛都可以进行以下操作:
(1) 将数字 $a_i从 a_i$ 变成 $a_i + b_i$ ;
(2) 将数字 $a_i从 a_i$ 变成 $a_i - b_i$ 。
牛牛很懒,所以每个数字只能最多进行一次操作,甚至不操作。现在给出一个数字 y ,牛牛想要知道在做合理的操作后能得到模 y 意义下的最大序列和是多少。
换句话说,设 $a_1' ,a_2', a_3'\dots a_n'$是最终得到的 数组的样子,你要使得 $(a_1' + a_2' + a_3'\dots +a_n') \ mod \ y$结果最大化。
做出这道题他就能起飞,你能帮帮他吗?
题解:
注意数据范围,b和y只有100,因此可以dp出来[0,y-1]这个区间内哪个点能到达,然后找到最大的
#include<iostream> #include<map> using namespace std; bool mapp[100005]; int a[100005],b[100005]; //map<int,bool> getpos; int getpos[105]; int main(){ int n,y; scanf("%d%d",&n,&y); int sum=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum=(sum+a[i])%y; } getpos[sum]=1; for(int i=1;i<=n;i++){ scanf("%d",&b[i]); for(int j=0;j<y;j++){ if(getpos[j]==1){ if(getpos[(j+b[i])%y]==0)getpos[(j+b[i])%y]=2; if(getpos[(j-b[i]+y)%y]==0)getpos[(j-b[i]+y)%y]=2; } } for(int j=0;j<y;j++){ if(getpos[j]==2)getpos[j]=1; } } int maxx=0; for(int i=0;i<y;i++){ if(getpos[i]==1)maxx=max(maxx,i); } printf("%d\n",maxx); return 0; }