矩阵快速幂

情书抄写员——高级
Time Limit: 1000MS Memory Limit: 1000K
   

Description

Wind的女友数量是惊人的。每个月开始时,Wind的每一个正式女友都会给他介绍k个新的女生,我们称这样的新人为“潜在的女友”(Potential GirlFriend)。通过近两个月的交往,潜在的女友总会在下一个月末成为正式的女友,并在第三个月初开始每月介绍新的女友。
我们假设,在第一个月Wind只有一个潜在的女友。Wind每个月都要给他的所有女友和潜在女友(包括本月初刚介绍来的人)写一封情书。在第a个月和第b个月,Wind有事不在,需要雇用一些“情书抄写员”来代替他完成这个操作。Wind将会让每个情书抄写员负责t封情书,并希望这个t值可以使得第a个月和第b个月的任务都能正好分尽。
Wind拜托“实习生”佳佳计算出第a个月和第b个月各需要写多少情书。为了雇用尽可能少的抄写员,Wind还想知道t的最大值是多少。
由于答案可能非常大,因此你只需要输出这三个数值mod m的结果即可。
数据规模
对于30%的数据,a; b; k ≤10;
对于80%的数据,a; b; k ≤100 000;
对于100%的数据,a; b; k ≤1 000 000 000,m ≤2的31次方- 1。
评分标准
本题设有部分分。
每个测试点共10分。
如果你的程序正确地输出了第a个月的值mod m(即第一行),则得3分;
如果你的程序正确地输出了第b个月的值mod m(即第二行),则得3分;
如果你的程序正确地输出了最大的t值mod m(即第三行),则得4分。
你需要给未输出的答案留下位置。也就是说,如果你选择不输出某个结果,你需要在结
果所在的位置留一个空行。
7

Input

输入数据一共只有一行,为四个用空格隔开的正整数,分别表示k、m、a和b,其意义如题目描述。

Output

输出数据一共有三行,每行输出一个数。
第一行为第a个月Wind需要写的情书数mod m的值;
第二行为第b个月Wind需要写的情书数mod m的值;
第三行为能同时整除第a个月的数目和第b个月的数目的最大值mod m的结果。

Sample Input

5 4 3 6

Sample Output

2
0
2

Hint

样例说明
第一个月只有一个潜在女友,第二个月该女友渐渐发展成熟,直到第三个月正式成为女
友并介绍了5个新的女生。因此,第三个月需要写6封情书,输出6 mod 4的结果,即2;
第四个月将再增加5人使得总人数达到11,到第五个月时将增加30个人。这样推下去可
以得到,第六个月需要写96封情书。数值6是能整除6和96的最大值。我们输出mod 4的结
果,即0和2。


前面是用矩阵快速幂

[好女友,即将好的女友][[1,k][1,0]]=[好女友,即将好的女友]

所以只要求出[[1,k][1,0]]的p-1次,就能算出第p月的好女友数


关键是后面的gcd(f(a),f(b))怎么算

斐波那契数列及其相似数列有这样一个性质gcd(f(a),f(b))=f(gcd(a,b))

这样就能轻松解决



#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
ll aa,bb,mm,kk;
struct Matrix
{
    ll mat[2][2];
};
Matrix mul(Matrix a,Matrix b)
{
    Matrix ret;
    for(ll i=0;i<2;i++){
    	for(ll j=0;j<2;j++)
        {
            ret.mat[i][j]=0;
            for(ll k=0;k<2;k++)
            {
                ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
    			ret.mat[i][j]%=mm;
            }
        }
    }
    return ret;
}
Matrix pow_M(Matrix a,ll n)
{
    Matrix ret;
    memset(ret.mat,0,sizeof(ret.mat));
    ret.mat[0][0]=ret.mat[1][1]=1;
    Matrix temp=a;
    while(n)
    {
        if(n&1)ret=mul(ret,temp);
        temp=mul(temp,temp);
        n>>=1;
    }
    return ret;
}
ll solve(ll a,ll b){
	ll tt=__gcd(a,b);
	return tt;
}
int main(){
	scanf("%lld%lld%lld%lld",&kk,&mm,&aa,&bb);
	Matrix dd;
	dd.mat[0][0]=dd.mat[1][0]=1;
	dd.mat[0][1]=kk;
	dd.mat[1][1]=0;
	Matrix ans1=pow_M(dd,aa-1);
	ll ans11=ans1.mat[0][0];//结果就是mat[0][0],不懂的话可以先理解一下矩阵
	ll tt1=ans11;
	Matrix ans2=pow_M(dd,bb-1);
	ll ans22=ans2.mat[0][0];
	ll tt2=ans22;
	ll t=solve(aa,bb);
	Matrix ans3=pow_M(dd,t-1);
	ll ts=ans3.mat[0][0];
	printf("%lld\n%lld\n%lld\n",ans11%mm,ans22%mm,ts%mm);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值