题意: 给出红蓝两种,然后排成一个字符串,要求在每一个长度为素数的区间里面是的r(red)的数量不小与b(blue)的数量;
思路:想象当n为2的时候的情况是 rr,rb,br,三种情况,当n为3的时候相当于在后面添加一个b或者r,会发现形成rr的情况是前面rr和br的和,形成br的情况是前面的rb,而形成rb的情况是前面的rr,不能有前面的br形成rb,因为在素数为3的时候不能形成brb;
所以你会发现这个针对的素数只是2和3;
根据递推,设数组a[],b[],c[]分别为后面两个字母为rr,br,rb的字符串的数量,那么可以得到递推式:
a[i] = a[i - 1] + c[i - 1];b[i] = a[i - 1];c[i] = b[i - 1];
而题中要求的是所有的字符串,即s[n] = a[n] + b[n] + c[n];
可以得出s[i] = s[i - 1] + s[i - 3];
n的范围是10^18,那么只能用到矩阵快速幂:
可以推出最初的矩阵为 1 0 1
1 0 0
0 1 0
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<string>
using namespace std;
#define clr(x,y) memset(x,y,sizeof x)
const int maxn = 1000000 + 10;
const double pp = 10e8;
typedef long long ll;
const ll SMod = 1000000007;
struct Matrix
{
ll m[3][3];
};
Matrix Mul(Matrix a,Matrix b)
{
Matrix c;
memset(c.m,0,sizeof(c.m));
for(ll i=0;i<3;i++)
for(ll j=0;j<3;j++)
for(ll k=0;k<3;k++)
c.m[i][j] += ((a.m[i][k]*b.m[k][j])%SMod + SMod)%SMod;
return c;
}
Matrix pow_mod(Matrix a,ll n)
{
Matrix res;
memset(res.m,0,sizeof(res.m));
res.m[0][0] = res.m[1][1] = res.m[2][2] = 1;
while(n)
{
if(n&1)
res = Mul(res,a);
n>>=1;
a = Mul(a,a);
}
return res;
}
Matrix p =
{
1,0,1,
1,0,0,
0,1,0
};
ll a[10];
int main()
{
ll Tcase;
scanf("%I64d",&Tcase);
a[2] = 3;
a[3] = 4;
a[4] = 6;
a[5] = 9;
while(Tcase --)
{
ll n;
scanf("%I64d",&n);
if(n <= 5)
{
printf("%I64d\n",a[n]);
continue;
}
Matrix t = pow_mod(p,n - 5);
ll ans = (t.m[0][0] * a[5] % SMod+ t.m[0][1] * a[4] %SMod + t.m[0][2] * a[3] %SMod ) % SMod;
printf("%I64d\n",ans);
}
return 0;
}