http://acm.hdu.edu.cn/showproblem.php?pid=6030
Happy Necklace
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1818 Accepted Submission(s): 755
Problem Description
Little Q wants to buy a necklace for his girlfriend. Necklaces are single strings composed of multiple red and blue beads.
Little Q desperately wants to impress his girlfriend, he knows that she will like the necklace only if for every prime length continuous subsequence in the necklace, the number of red beads is not less than the number of blue beads.
Now Little Q wants to buy a necklace with exactly n beads. He wants to know the number of different necklaces that can make his girlfriend happy. Please write a program to help Little Q. Since the answer may be very large, please print the answer modulo 109+7.
Note: The necklace is a single string, {not a circle}.
Input
The first line of the input contains an integer T(1≤T≤10000), denoting the number of test cases.
For each test case, there is a single line containing an integer n(2≤n≤1018), denoting the number of beads on the necklace.
Output
For each test case, print a single line containing a single integer, denoting the answer modulo 109+7.
Sample Input
2
2
3
Sample Output
3
4
Source
题意理解
给你一个长度为n的字符串,只包含0和1,要求这个字符串的所有素数长度的子序列(2,3)都是1的个数比0的个数多,问长度为n的这样字符串有多少个?
思路
首先我们发现,当满足素数区间2,素数区间3的条件之后,下一个素数区间5乃至于之后的所有都会满足。(因为满足素数区间2,素数区间3的条件更强) 然后我们假设现在有一个数目为n的方案数为f(n)。假设红的为1 蓝的为0 从而将此题简化成满足1的个数大于等于0的个数的一个二进制字符串的方案数) 那么我们考虑一下,能否从f(n-1)转移到f(n)呢?
考虑这个n-1位,后边如果加一个1,那么一定符合条件。(所以方案数可以加一个f(n-1))
那。如果最后一位加的是0呢? 此时我们不难发现,倒数第二位一定是1,只有这样才能满足素数区间2的条件。
进而得出倒数第三位一定是1,否则不能满足素数区间3的条件。 所以我们得出结论:f(n) = f(n-1) + f(n-3)
但是还没完,n的范围太大,我们无法将递推得到的结果保存起来。然而每次都递推又太慢,所以:矩阵快速幂。
原矩阵、递推矩阵:(因为递推1次得到F(5),递推2次得到F(6),若得到F(n),需要递推(n-4)次
AC Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll nmax=3;
const ll MOD=1e9+7;
#define mod(x) ((x)%MOD)
int n;
struct mat{
ll m[nmax][nmax];
}unit;
//A*B^(n-2)=C //C矩阵的首项即为f(n)
mat operator *(mat a,mat b){
mat ret;
ll x;
for(ll i=0;i<nmax;i++){//3*3
for(int j=0;j<nmax;j++){
x=0;
for(ll k=0;k<nmax;k++){
x+=mod((ll)a.m[i][k]*b.m[k][j]);
}
ret.m[i][j]=mod(x);
}
}
return ret;
}
void init_unit(){
for(ll i=0;i<nmax;i++){
unit.m[i][i]=1;
}
return;
}
mat pow_mat(mat a,ll n){//求矩阵a的n次幂
mat ret=unit;
while(n){
if(n&1) ret=ret*a;
a=a*a;
n>>=1;
}
return ret;
}
int main(int argc, char** argv) {
ll n,t;
init_unit();
scanf("%lld",&t);
while(t--){//需要求矩阵B的n-2次幂
scanf("%lld",&n);
if(n==2) printf("3\n");
else if(n==3) printf("4\n");
else if(n==4) printf("6\n");
else{
mat a,b;
b.m[0][0]=1;b.m[0][1]=1;b.m[0][2]=0;
b.m[1][0]=0;b.m[1][1]=0;b.m[1][2]=1;
b.m[2][0]=1;b.m[2][1]=0;b.m[2][2]=0;
a.m[0][0] = 6,a.m[0][1] = 4,a.m[0][2] = 3;
a.m[1][0] = 0,a.m[1][1] = 0,a.m[1][2] = 0;
a.m[2][0] = 0,a.m[2][1] = 0,a.m[2][2] = 0;
b=pow_mat(b,n-4);
a=a*b;
//printf("%lld\n",mod(a.m[0][0]));
printf("%lld\n",a.m[0][0]%MOD);
}
}
return 0;
}