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的数,后面的同理

说完了..

原文地址:https://www.cnblogs.com/guaguastandup/p/10353720.html

时间: 2024-08-02 16:42:15

codeforces round 533 div2 C Ayoub and Lost Array [dp]的相关文章

codeforces round #257 div2 C、D

本来应该认真做这场的,思路都是正确的. C题,是先该横切完或竖切完,无法满足刀数要求,再考虑横切+竖切(竖切+横切), 因为横切+竖切(或竖切+横切)会对切割的东西产生交叉份数,从而最小的部分不会尽可能的大. 代码如下,虽然比较长.比较乱,但完全可以压缩到几行,因为几乎是4小块重复的代码,自己也懒得压缩 注意一点,比如要判断最小块的时候,比如9行要分成2份,最小的剩下那份不是9取模2,而应该是4 m/(k+1)<=m-m/(k+1)*k          #include<bits/stdc+

codeforces Round #250 (div2)

a题,就不说了吧 b题,直接从大到小排序1-limit的所有数的lowbit,再从大到小贪心组成sum就行了 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200000 6 using namespace std; 7 int pos[N],a[N],s[N],f[N],la[N],b[N],i,j,k,ans,n,p

Codeforces Round#320 Div2 解题报告

Codeforces Round#320 Div2 先做个标题党,骗骗访问量,结束后再来写咯. codeforces 579A Raising Bacteria codeforces 579B Finding Team Member codeforces 579C A Problem about Polyline codeforces 579D "Or" Game codeforces 579E Weakness and Poorness codeforces 579F LCS Aga

Codeforces Round #254(div2)A

很有趣的题.想到了就非常简单,想不到就麻烦了. 其实就是一种逆向思维:最后结果肯定是这样子: WBWBWBWB... BWBWBWBW... WBWBWBWB... ... 里面有“-”的地方改成“-”就行了. 但是我开始是正着想的,想每个点怎么处理,这还要看它周围点的状态,越想越麻烦... 这题中体现的正难则反的逆向思维很值得学习. #include<iostream> #include<cstdio> #include<cstdlib> #include<cs

Codeforces Round #254(div2)B

就是看无向图有几个连通块,答案就是2n-num. 范围很小,就用矩阵来存图减少代码量. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #inc

Codeforces Round #260(div2)C(递推)

有明显的递推关系: f[i]表示i为数列中最大值时所求结果.num[i]表示数i在数列中出现了几次. 对于数i,要么删i,要么删i-1,只有这两种情况,且子问题还是一样的思路.那么很显然递推一下就行了:f[i]=max(f[i-1],f[i-2]+i*num[i]); 这里技巧在于:为了防止麻烦,干脆就所有数的出现次数都记录一下,然后直接从2推到100000(类似于下标排序),就不用排序了,也不用模拟删除操作了.这一技巧貌似简单,但实际上临场想出来也需要点水平. #include<iostrea

Codeforces Round #289 Div2 E

Problem 给一串长度为N的字符串,对于每个字符,若字符为元音,则权值为1,否则为0.一个子串的权值定义为该串所有字符权值之和除以字符个数,一个母串的权值定义为所有子串的权值之和.求母串的权值. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N: [1, 5*10^5] 字符集: 'A'-'Z' 元音: I E A O U Y Solution 考虑每个元音字符对母串的贡献,可以找出规律. More 举"ABCDOEFGHKMN"

Codeforces Round #403 div2 C. Andryusha and Colored Balloons

题目链接:Codeforces Round #403 div2 C. Andryusha and Colored Balloons 题意: 给你一棵n个节点的树,然后让你染色,规定相连的三个 节点不能同色,问需要的最少颜色,并输出其中一种方案. 题解: 因为只有相邻3个节点不同色. 所以直接DFS,每个节点都从1开始. 然后ans[v]!=ans[u]!=ans[fa]就行. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i&

CodeForces Round#229 DIV2 C 递推DP

对这道题目也只好说呵呵了,没注意k的范围最大才10,所以昨晚纠结了很久,没什么好的方法来处理,后来无奈想去翻翻题解,发现人家开头就来了句,因为k的范围比较小 所以.........我只好暂停马上回头看看题目,是的,k比较小所以完全可以先在询问前预处理DP一遍, DP就比较清晰了,dp[i][j]  (i>=0 && i<k,,,,j>=i && j <=n)代表意义呢 以i为开头的  区间[1,j]注意 是 1~j的 所需要的操作数,题目问的是最小操