https://ac.nowcoder.com/acm/problem/15666
给定 f ( 0 ) = 0 , f ( 1 ) = 1 f(0)=0,f(1)=1 f(0)=0,f(1)=1
f i = f i − 1 + f i − 2 + i + i 2 + i 3 + 1 f_i=f_{i-1}+f_{i-2}+i+i^2+i^3+1 fi=fi−1+fi−2+i+i2+i3+1
求 f n f_n fn,答案对 1 0 9 + 7 10^9+7 109+7取模
数据范围: n ≤ 1 0 18 n\leq 10^{18} n≤1018
暴力好打吧。。。
50分
#include
#define mod 1000000007
using namespace std;int n,t;
long long f[1000001];
signed main()
{
f[0]=0;f[1]=1;
for(register int i=2;i<=1000000;i++) (f[i]=f[i-1]+f[i-2]+1ll*i*i*i%mod+1ll*i*i%mod+i+1ll)%=mod;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%lld\n",f[n]);
}
}
其实这道题要是没有 i 3 , i 2 i^3,i^2 i3,i2限制就是 s b sb sb题了,考虑如何发shit规律
把三次方写出来
p3=1 8 27 64 125 216
做差分
add=7 19 37 61 91
二次差分,得到等差数列
gc3=12 18 24 30
同理把平方写出来
p2=1 4 9 16 25 36
差分直接得到等差数列
gc2=3 5 7 9 11 13
于是
1 = 1 1=1 1=1
i = i − 1 + 1 i=i-1+1 i=i−1+1
g c 2 i = g c 2 i − 1 + 2 gc2_i=gc2_{i-1}+2 gc2i=gc2i−1+2
p 2 i = p 2 i − 1 + g c 2 i − 1 p2_i=p2_{i-1}+gc2_{i-1} p2i=p2i−1+gc2i−1
g c 3 i = g c 3 i − 1 + 6 gc3_i=gc3_{i-1}+6 gc3i=gc3i−1+6
a d d i = a d d i − 1 + g c 3 i − 1 add_i=add_{i-1}+gc3_{i-1} addi=addi−1+gc3i−1
$p3_i=p3_{i-1}+add_{i-1} $
f i − 1 = f i − 1 f_{i-1}=f_{i-1} fi−1=fi−1
f i = f i − 1 + f i − 2 + p 3 i − 1 + a d d i − 1 + p 2 i − 1 + g c 2 i − 1 + i − 1 + 2 f_i=f_{i-1}+f_{i-2}+p3_{i-1}+add_{i-1}+p2_{i-1}+gc2_{i-1}+i-1+2 fi=fi−1+fi−2+p3i−1+addi−1+p2i−1+gc2i−1+i−1+2
矩阵转移即可
注意到我们最少从第二项开始转移,所以预处理 i = = 2 i==2 i==2时的各项数组
1 = 1 1=1 1=1
i = 2 i=2 i=2
g c 2 i = 5 gc2_i=5 gc2i=5
g c 3 i = 18 gc3_i=18 gc3i=18
a d d i = 19 add_i=19 addi=19
p 2 i = 4 p2_i=4 p2i=4
p 3 i = 8 p3_i=8 p3i=8
后面这两个往后移一位(这样方便转移,否则就要将原递推式进一步拆分)
f i − 2 = 1 f_{i-2}=1 fi−2=1
f i − 1 = 16 f_{i-1}=16 fi−1=16
时间复杂度: O ( T k 3 l o g n ) O(Tk^3logn) O(Tk3logn)
在作者的解法中 k = 9 k=9 k=9,有些最终结果并非直接得到而是间接转移的 k = 6 k=6 k=6,但是矩阵会麻烦很多
一些杂七杂八的话:这道题是作者在一站到底的时候刷的第一题,最后一分钟过了,真的刺激。。。。
#include
#include
#define ymw 1000000007
using namespace std;int t;
long long n;
struct node{long long a[9][9];};
const int d[9][9]=
{
{1,1,2,6,0,0,0,0,2},
{0,1,0,0,0,0,0,0,1},
{0,0,1,0,0,1,0,0,1},
{0,0,0,1,1,0,0,0,0},
{0,0,0,0,1,0,1,0,1},
{0,0,0,0,0,1,0,0,1},
{0,0,0,0,0,0,1,0,1},
{0,0,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,1,1},
};
const int e[9]={1,2,5,18,19,4,8,1,16};
inline node mul(node x,node y)
{
node z;
memset(&z,0,sizeof(z));
for(register int i=0;i<9;i++)
for(register int j=0;j<9;j++)
for(register int k=0;k<9;k++)
z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%ymw)%ymw;
return z;
}
inline long long ksm(register long long y)
{
node x,ans;
memset(&x,0,sizeof(x));
memset(&ans,0,sizeof(ans));
for(register int i=0;i<9;i++)
for(register int j=0;j<9;j++)
x.a[i][j]=d[i][j];
for(register int i=0;i<9;i++) ans.a[0][i]=e[i];
while(y)
{
if(y&1) ans=mul(ans,x);
x=mul(x,x);
y>>=1;
}
return ans.a[0][8];
}
signed main()
{
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
if(n==0) putchar(48);
else if(n==1) putchar(49);
else printf("%lld",ksm(n-2));
putchar(10);
}
}