题目来源: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; }