hdu6395(分段矩阵快速幂)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yu121380/article/details/81665397

Sequence

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1039    Accepted Submission(s): 388

Problem Description

Let us define a sequence as below



  Your job is simple, for each task, you should output Fn module 109+7.

Input

The first line has only one integer T, indicates the number of tasks.

Then, for the next T lines, each line consists of 6 integers, A , B, C, D, P, n.

1≤T≤200≤A,B,C,D≤1091≤P,n≤109

Sample Input

2

3 3 2 1 3 5

3 2 2 2 1 4

Sample Output

36

24

Source

2018 Multi-University Training Contest 7

分段的矩阵快速幂要注意过程的转换,矩阵要回归最初的状态。

解析:向下取整的P/i在1~n中,会有重复的值,说明我们可以分段矩阵快速幂。二分查找相等的P/i的区间。(也可以O(1)目前不会,数论分块里应该有说明。)

构造的矩阵:

#include<bits/stdc++.h>
using namespace std;

#define e exp(1)
#define pi acos(-1)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define mem(a,b) memset(a,b,sizeof(a))
int gcd(int a,int b){return b?gcd(b,a%b):a;}

ll A,B,C,D,N,P;
struct mat  
{
    ll a[3][3];
}c;
mat mat_mul(mat x,mat y)  
{
    mat s;  
    mem(s.a,0);
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        for(int k=0;k<3;k++)
        s.a[i][j]=(s.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
        
    return s;
}
mat mat_pow(ll n)
{
	mat res;
	mem(res.a,0);
	res.a[0][0]=res.a[1][1]=res.a[2][2]=1;
    while(n)
    {
        if(n&1) res=mat_mul(res,c);  
        c=mat_mul(c,c);  
        n>>=1;
    }
    return res;
}
ll solove(ll i)
{
	ll l=i,r=N;
	ll p=P/i;
	while(l<r)
	{
		int mid=r-(r-l)/2;
		if(p==P/mid)l=mid;
		else if(p>P/mid)r=mid-1;
		else l=mid+1;
	}
	return l;
}

int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld%lld%lld%lld",&A,&B,&C,&D,&P,&N);
		if(N==1){printf("%lld\n",A);continue;}
		if(N==2){printf("%lld\n",B);continue;}

		ll f1=B;
		ll f2=A;
		
		mat ans;
		for(ll i=3; i<=N;)
		{
			ll j=solove(i);
			
			mem(c.a,0);
			c.a[0][0]=D;c.a[0][1]=C;
			c.a[2][2]=1;c.a[1][0]=1;
			c.a[0][2]=P/i;
			ans=mat_pow(j-i+1);
			
			ll ff1=(ans.a[0][0]*f1%mod+ans.a[0][1]*f2%mod+ans.a[0][2])%mod;
			ll ff2=(ans.a[1][0]*f1%mod+ans.a[1][1]*f2%mod+ans.a[1][2])%mod;
			
			f1=ff1;
			f2=ff2;
			
			i=j+1;
		}
		printf("%lld\n",f1);
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yu121380/article/details/81665397
今日推荐