• POJChallengeRound2 Guideposts 【单位根反演】【快速幂】


    题目分析:

    这题的目标是求$$ sum_{i in [0,n),k mid i} inom{n}{i}G^i $$

    这个形式很像单位根反演。

    单位根反演一般用于求:$ sum_{i in [0,n),k mid i} inom{n}{i}f(x)^i $

    推理过程略,实际上也就是交换求和符号的事情。

    接着就变成裸的矩阵快速幂了

    代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 
      4 int m,k,p;long long n;
      5 int l,s,t,gg;
      6 
      7 struct mat{int arr[7][7];}G,bs,mmp;
      8 vector<int> fac; // factor of p
      9 
     10 void buildbase(int w){
     11     for(int i=1;i<=m;i++)
     12     for(int j=1;j<=m;j++) bs.arr[i][j] = 1ll*w*G.arr[i][j]%p;
     13     for(int i=1;i<=m;i++) bs.arr[i][i] ++,bs.arr[i][i] %= p;
     14 }
     15 
     16 mat operator*(mat alpha,mat beta){
     17     memset(mmp.arr,0,sizeof(mmp.arr));
     18     for(int k=1;k<=m;k++){
     19     for(int i=1;i<=m;i++){
     20         for(int j=1;j<=m;j++){
     21         mmp.arr[i][j] += 1ll*alpha.arr[i][k]*beta.arr[k][j]%p;
     22         mmp.arr[i][j] %= p;
     23         }
     24     }
     25     }
     26     return mmp;
     27 }
     28 
     29 mat res;
     30 mat fstpow(mat now,long long pw){
     31     memset(res.arr,0,sizeof(res.arr));
     32     for(int i=1;i<=m;i++) res.arr[i][i] = 1;
     33     long long bit = 1;
     34     while(bit <= pw){
     35     if(bit & pw){res = res*bs;}
     36     bs = bs*bs;bit<<=1;
     37     }
     38     return res;
     39 }
     40 
     41 void init(){
     42     memset(G.arr,0,sizeof(G.arr));
     43     fac.clear();
     44     l = s = t = gg = 0;
     45 }
     46 
     47 void read(){
     48     scanf("%d%d%d",&l,&s,&t);
     49     for(int i=1;i<=l;i++){
     50     int u,v; scanf("%d%d",&u,&v);
     51     G.arr[u][v]++;
     52     }
     53 }
     54 
     55 int fast_pow(int now,int pw){
     56     int ans = 1,dt = now,bit = 1;
     57     while(bit <= pw){
     58     if(bit & pw){ans = 1ll*ans*dt%p;}
     59     dt = 1ll*dt*dt%p; bit<<=1;
     60     }
     61     return ans;
     62 }
     63 
     64 void getgg(){
     65     int z = p-1;
     66     for(int i=2;i*i<=z;i++){
     67     if(z % i == 0){
     68         fac.push_back(i);
     69         while(z % i == 0) z /= i;
     70     }
     71     }
     72     if(z != 1) fac.push_back(z);
     73     for(int i=2;i<=p;i++){
     74     int flag = true;
     75     for(int j=0;j<fac.size();j++){
     76         int z = fast_pow(i,(p-1)/fac[j]);
     77         if(z == 1){flag = false; break;}
     78     }
     79     if(flag){gg = i;break;}
     80     }
     81     gg = fast_pow(gg,(p-1)/k);
     82 }
     83 
     84 void work(){
     85     int w = 1,ans = 0;
     86     for(int i=0;i<k;i++,w = 1ll*w*gg%p){
     87     buildbase(w);
     88     bs = fstpow(bs,n);
     89     ans += bs.arr[s][t]; ans%=p;
     90     }
     91     ans = 1ll*ans*fast_pow(k,p-2)%p;
     92     printf("%d
    ",ans);
     93 }
     94 
     95 int main(){
     96     while(scanf("%d%lld%d%d",&m,&n,&k,&p) == 4){
     97     init();
     98     read();
     99     getgg();
    100     work();
    101     }
    102     return 0;
    103 }

     

  • 相关阅读:
    推导式
    解构
    for 循环
    运算符
    while 循环
    流程控制语句
    索引和切片
    ASC转换BCD,ASC2BCD(转)
    CString和char互转,十六进制的BYTE转CString
    C++添加简单的日记记录
  • 原文地址:https://www.cnblogs.com/Menhera/p/10394970.html
Copyright © 2020-2023  润新知