• C. Ayoub and Lost Array


    题目来源:http://codeforces.com/contest/1105/problem/C

    题意:给出一个数组的长度以及数组中元素的取值范围,问:有多少种方案使得数组的元素的总和为三的倍数。

    解题思路:我们可以把可取的数字分为三类:对三取模为零,对三取模为一,对三取模为二。先分别统计这三类取值的个数,先假设个数分别为a,b,c,然后定义某个状态dp【i】【j】为数组长度为i的总和对三取模的值的方案数,那么可以得到dp【i+1】【0】=dp【i】【0】*a+dp【i】【1】*c+dp【i】【j】*b,dp【i+1】【1】=dp【i】【0】*b+dp【i】【1】*a+dp【i】【2】*c,dp【i】【2】=dp【i】【0】*c+dp【i】【1】*b+dp【i】【2】*a。最后答案就是:dp【n】【0】。

     #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<stack>
    #include<cstdio>
    #include<map>
    #include<set>
    #include<string>
    #include<queue>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define mod 1000000007LL
    typedef long long ll;
    inline ll gcd(ll i,ll j){
        return j==0?i:gcd(j,i%j);
    }
    inline ll lcm(ll i,ll j){
        return i/gcd(i,j)*j;
    }
    int f(int a,int b){
        return a-b>0?a-b:b-a;
    }
    const int maxn=2e5+10;
    ll dp[maxn][5];
    int main(){
        int n,l,r;
        scanf("%d%d%d",&n,&l,&r);
        ll a,b,c,k,k1;
        a=b=c=(r-l+1)/3;
        for(int i=0;i<(r-l+1)%3;i++){
            if((l+i)%3==0)
            a++;
            else if((l+i)%3==1)
            b++;
            else
            c++;
        }
        dp[1][0]=a;
        dp[1][1]=b;
        dp[1][2]=c;
        for(int i=2;i<=n;i++){
            dp[i][0]=(dp[i-1][0]*a%mod+dp[i-1][1]*c%mod+dp[i-1][2]*b%mod)%mod;
            dp[i][1]=(dp[i-1][0]*b%mod+dp[i-1][1]*a%mod+dp[i-1][2]*c%mod)%mod;
            dp[i][2]=(dp[i-1][0]*c%mod+dp[i-1][1]*b%mod+dp[i-1][2]*a%mod)%mod;
        } 
        cout<<dp[n][0];
        return 0;
    }

    既然得到了状态转移方程,那么也很容易用矩阵来得到答案了

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<stack>
    #include<cstdio>
    #include<map>
    #include<set>
    #include<string>
    #include<queue>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define mod 1000000007LL
    typedef long long ll;
    inline ll gcd(ll i,ll j){
        return j==0?i:gcd(j,i%j);
    }
    inline ll lcm(ll i,ll j){
        return i/gcd(i,j)*j;
    }
    struct st{
        ll mp[3][3];
        void init(){
            for(int i=0;i<3;i++){
                for(int j=0;j<3;j++){
                    mp[i][j]=(i==j);
                }
            }
        }
    }tem1,tem2;
    st mul(st a,st b){
        st c;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                c.mp[i][j]=0;
            }
        }
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                for(int k=0;k<3;k++){
                    c.mp[i][j]=(c.mp[i][j]+a.mp[i][k]*b.mp[k][j]%mod)%mod;
                }
            }
        }
        return c;
    }
    st q_pow(st a,int n){
        st b;
        b.init();
        while(n!=0){
            if(n%2==1){
                b=mul(a,b);
            }
            a=mul(a,a);
            n/=2;
        }
        return b;
    }
    int main(){
        int n,l,r;
        scanf("%d%d%d",&n,&l,&r);
        ll a,b,c,k,k1;
        a=b=c=(r-l+1)/3;
        for(int i=0;i<(r-l+1)%3;i++){
            if((l+i)%3==0)
            a++;
            else if((l+i)%3==1)
            b++;
            else
            c++;
        }
        tem1.mp[0][0]=a;
        tem1.mp[0][1]=b;
        tem1.mp[0][2]=c;
        tem2.mp[0][0]=a;tem2.mp[0][1]=b;tem2.mp[0][2]=c;
        tem2.mp[1][0]=c;tem2.mp[1][1]=a;tem2.mp[1][2]=b;
        tem2.mp[2][0]=b;tem2.mp[2][1]=c;tem2.mp[2][2]=a;
        cout<<mul(tem1,q_pow(tem2,n-1)).mp[0][0];
        return 0;
    }
  • 相关阅读:
    关于Unicode的小理解
    大数据高并发学习笔记(3)
    大数据高并发学习笔记(2)
    .net阻止XSS攻击方法
    VUE-百度地图添加覆盖物及信息窗口添加导航功能
    第34章:高级全局API钩取 : IE连接控制
    第2章:动态调试技术--OllyDbg
    第33章:隐藏进程-API代码修改技术(下)
    第33章:隐藏进程-API代码修改技术(中)
    第1章:基础知识
  • 原文地址:https://www.cnblogs.com/Zhi-71/p/10309284.html
Copyright © 2020-2023  润新知