牛客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;
}

 

posted @ 2021-01-01 09:09  Isakovsky  阅读(85)  评论(0编辑  收藏  举报