BestCoder Round #80 A B C hdu5667矩阵快速幂



链接:戳这里


Lucky
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
    Vampire喜欢玄学,尤其喜欢研究幸运数字.

     对于一个数字集合S,定义关于S的幸运数字为无法用S中的数相加得到的最小的非负整数(每个数可以使用任意次).

     现在给定一个数集,如果能使用其中的数相加得到任意自然数,输出”YES”,否则输出”NO”.
输入描述
   第一行一个正整数T,为数据组数.

    每组数据第一行一个n,表示集合大小.

   接下来n个数,表示该数集里的数.

 1≤n≤10^​5,1≤T≤10,0≤a​i≤10^9
输出描述
  每组数据回答一个”YES”或”NO”.
输入样例
1
1
2
输出样例
NO


思路:

因为每个数可以用很多次,所以只要这个集合中有1,那么就可以加出所有的数来.注意最后要判定一下是否有0.


代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int a[1000100];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int flag1=0,flag2=0;
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            if(a[i]==1){
                flag1=1;
            }
            if(a[i]==0){
                flag2=1;
            }
        }
        if(flag1 && flag2) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}


Segment
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
  Rivendell非常神,喜欢研究奇怪的问题.

  今天他发现了一个有趣的问题.找到一条线段x+y=qx+y=q,令它和坐标轴在第一象限围成了一个三角形,然后画线连接了坐标原点和线段上坐标为整数的格点.

 请你找一找有多少点在三角形的内部且不是线段上的点,并将这个个数对PP取模后告诉他.
输入描述
  第一行一个数T,为测试数据组数.

  接下来每一行两个数qq,PP,意义如题目中所示.

q是质数且q≤10^18,1≤P≤10^18,1≤T≤10.
输出描述
   对每组数据,输出点的个数模PP后的值.
输入样例
1
2 107
输出样例
0


思路:

考虑一条以(0,0)为起点,(x,y)为终点的线段上格点的个数(不包含端点时),一定是gcd(x,y)-1,这个很显然吧.
然后整个网格图范围内的格点数目是q*(q-1)/2
所以答案就是q*(q-1)/2 − 所有线段上的格点的个数.
因为q是质数且a+b=q可以推出gcd(a,b)=1

 显然答案就是计算等腰直角三角形中的格点数 


代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll Q,P;
ll kuai(ll q,ll num,ll mod){
    ll ans=0;
    ll base=q;
    while(num){
        if(num%2) ans=(ans+base)%mod;
        num/=2;
        base=(base+base)%mod;
    }
    return ans%mod;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        cin>>Q>>P;
        ll ans=(Q-1)/2;
        ans=kuai(ans,Q-2,P);
        cout<<(ans+P)%P<<endl;
    }
    return 0;
}


Sequence 
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
 Lcomyn 是个很厉害的选手,除了喜欢写17kb+的代码题,偶尔还会写数学题.他找到了一个数列:



  他给了你几个数:nn,aa,bb,cc,你需要告诉他fn模p后的数值.
输入描述
第一行一个数T,为测试数据组数.

 每组数据一行,一行五个正整数,按顺序为nn,aa,bb,cc,pp.
1≤T≤10,1≤n≤10^18 ,1≤a,b,c≤10^9 ,p是质数且 p≤10​^9​​ +7.
输出描述
对每组数据输出一行一个数,输出fn对p取模后的数值.
输入样例
1
5 3 3 3 233
输出样例
190


思路:

观察递推式我们可以发现,所有的  f​i都是a的幂次,所以我们可以对f​i取一个以a为底的log

即g​i=log(a,fi)
那么递推式变成g​i =b+c∗g[​i−1]+g[​i−2]
​​ ,这个式子可以矩阵乘法
这题有一个小trick,注意a mod p=0的情况.


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
struct Matrix{
    ll ma[3][3];
    Matrix(){
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                ma[i][j]=0;
    }
};
ll n,A,B,C,P;
Matrix Mult(Matrix b,Matrix a,ll p){
    Matrix ans;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            for(int k=0;k<3;k++){
                ans.ma[i][j]=(ans.ma[i][j]+a.ma[i][k]*b.ma[k][j]%p)%p;
            }
        }
    }
    return ans;
}
Matrix MPow(Matrix a,ll num,ll p){
    Matrix tmp;
    for(int i=0;i<3;i++) tmp.ma[i][i]=1;
    while(num){
        if(num%2) tmp=Mult(tmp,a,p);
        a=Mult(a,a,p);
        num/=2;
    }
    return tmp;
}
ll Pow(ll a,ll b,ll p){
    ll ans=1;
    while(b){
        if(b%2) ans=ans*a%p;
        a=a*a%p;
        b/=2;
    }
    return ans;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        cin>>n>>A>>B>>C>>P;
        Matrix a,b;
        a.ma[0][0]=1;a.ma[2][0]=B;
        b.ma[0][0]=1;b.ma[1][2]=1;
        b.ma[2][0]=B;b.ma[2][1]=1;b.ma[2][2]=C;
        if(n==1) cout<<1<<endl;
        else if(n==2) printf("%I64d\n",Pow(A,B,P));
        else {
            if(A%P==0) cout<<0<<endl;
            else {
                Matrix tmp=MPow(b,n-2,P-1);
                Matrix ans=Mult(a,tmp,P-1);
                ll anw=Pow(A,ans.ma[2][0],P);
                printf("%I64d\n",anw);
            }
        }
    }
    return 0;
}<strong>
</strong>


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值