codeforces round 533 div2 C Ayoub and Lost Array [dp]

一道思维题

不仅是和这道题在战斗,我和编译器也进行了一场激烈的角逐
因为编译器出了点小问题...
对于dev或者codeblocks 我的方法是卸载了重新装/重启电脑
但是对于vscode 我的方法是,
对着它掉眼泪,看它能不能可怜可怜我,赶紧恢复到正常状态....

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define int long long
const ll N = 2e5 + 1000;
const  ll mod = 1e9 + 7;
ll n, dp[N][3],l,r,n0,n1,n2;
int main(){
    scanf("%ld%ld%ld", &n,&l,&r);
    n0= n1 = n2 = (r - l + 1) / 3;
    ll num = (r - l + 1) % 3;
      if(num==1){
        if(r%3==2)
            n2++;
        else if(r%3==1)
            n1++;
        else if(r%3==0)
            n0++;
    }
    else if(num==2){
        if(r%3==1){
            n0++;
            n1++;
        }
        else if(r%3==2){
            n1++;
            n2++;
        }
        else if(r%3==0){
            n0++;
            n2++;
        }
    }
    dp[1][0] = n0;
    dp[1][1] = n1;
    dp[1][2] = n2;
    for (ll i = 2; i <= n; i++){
        dp[i][0] = ( (dp[i - 1][0] * n0)%mod + (dp[i - 1][1] * n2)%mod + (dp[i - 1][2] * n1)%mod )%mod;
        dp[i][1] = ( (dp[i - 1][0] * n1)%mod + (dp[i - 1][1] * n0)%mod + (dp[i - 1][2] * n2)%mod )%mod;
        dp[i][2] = ( (dp[i - 1][0] * n2)%mod + (dp[i - 1][1] * n1)%mod + (dp[i - 1][2] * n0)%mod )%mod;
    }
    cout << dp[n][0];
    //system("pause");
    return 0;
}

这道题,各个版本的解析都说的很简单,我想详细的说一下

题意:

给定一个闭区间,[l,r],要在里面选n个数,保证n个数的和为3的倍数

思路:数论+dp

关于数论部分:

    要让n个数的和为3,比如现在有两个数,a和b
   
    有一个简单的前置计划式子,那就是:
            ((a mod n)+(b mod n) )mod n==(a+b)mod n; 
    减法和乘法同理;

    那么能够满足a+b=3*k,即(a+b)%3==0 也就是 
    [(a%3)+(b%3) ]%3==0
    如果a%3==1,那么b%3为2;
    如果a%3==0,那么b%3为0;
    如果a%3==2,那么b%3为1
    这样才能保证两个数相加能够被3整除

关于dp部分

    这里的dp我们用一个二维数组表示,dp[N][3];
    对于dp[i][j];
    i代表目前已经选择了i个数相加,j表示他们的和的余数目前是0或1或2;
    dp数组的值代表选择i个数相加,并且它们的和的余数为0/1/2有多少种;
    在for循环里,每一次i++,我们都要选取一个新的数加进我们选择的数组,最后直到我们已经选完了n个数;
    那么每次选的时候,比如说我们现在是
    dp[i][2] = ( (dp[i - 1][0] * n2)%mod + (dp[i - 1][1] * n1)%mod + (dp[i - 1][2] * n0)%mod )%mod;
    对于这个式子,那么就是我们现在已经有i-1个数已经排列好了,并且之前有多少种可能性已经计算过了,现在想再加一个数进去,构成一个长度为i的,和的余数为2的数组;
    现在我们想在原本的i-1序列中加一个数,使得和的余数为2,
    那么对于dp[i-1][0],要乘上余数为2的数的数量,也就是dp[i-1][0]*n2,这样才可以得到一个余数为2的数,后面的同理

说完了..

猜你喜欢

转载自www.cnblogs.com/guaguastandup/p/10353720.html