15145641

  额,这个题也做了好几天了,中间停停断断的……

  一开始写是超时,想到了正确的思路,用dp[i][j]代表到i个珠子颜色为j的方案数,但是超时了,因为我细节处理的太差,我先枚举了初始状态,然后又枚举了结束状态,多了两个m,因为我想的是判断最后一个和第一个的关系,但其实完全可以让矩阵帮助我多做一次运算,找对应的值就可以,所以结束状态是不需要枚举的,开始状态可以把原先1*N的初始矩阵,改成N*N的矩阵,这里正好是单位阵,每一行都代表一个独立的初始状态,矩阵在计算的时候,就会把答案存储到自身对应的行,最终只要把对角线上的求和即可。这样是很聪明的做法,因为这个题目数据太强,差一点都不行,但是我又不敢减少取模,因为怕溢出。

  但是今晚改了之后,发现WA了,我一直都以为n的因子不会超过两百个,但是我自己生成数据拍出了288个因子,干脆改成2000过去了,后来发现因子会多于1000个,这也是很符合道理的,算是纠正了我一个误区吧。以后尽量有vector存储吧。但是有意思的是,这个题其实不需要存……是我多此一举了

  代码:

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define LL long long
const int Mod = 9973;
int n,m,k,ok[12][12];
struct Mar{
    int n,m,a[12][12];
    Mar(int nn,int mm){
        n=nn; m=mm;
        memset(a,0,sizeof(a));
    }
    Mar operator*(const Mar&B)const{
        Mar C(n,B.m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]){
                    for(int k=1;k<=B.m;k++){
                        C.a[i][k]=(C.a[i][k]+a[i][j]*B.a[j][k]%Mod)%Mod;
                    }

                }
            }
        }
        return C;
    }
};
Mar MarPow(Mar x,int y){
    Mar res(x.n,x.m);
    for(int i=1;i<=x.n;i++){
        res.a[i][i] = 1;
    }
    while(y){
        if(y&1){
           res = res*x;
        }
        x = x*x;
        y>>=1;
    }
    return res;
}
//#include<cmath>
int yz[2000],lyz;
int p[4600],pct;
bool isp[32622];
void init(){
    memset(isp,0,sizeof(isp));
    pct=0; int up = 32600;
    for(int i=2;i<=up;i++){
        if(!isp[i]){
            p[pct++] = i;
        }
        for(int j=0;j<pct;j++){
            LL x = 1LL*p[j]*i;
            if(x > 1LL*up) break;
            isp[x] = 1;
            if(i%p[j]==0) break;
        }
    }
//    cout<<pct<<endl;
}
int Euler(LL x){
    LL res = x;
    for(int i=0;i<pct;i++){
        if(1LL*p[i]*p[i] > x) break;
        if(x == 1) break;
        if(x%p[i]==0){
            res = res/p[i]*(p[i]-1);
            x /= p[i];
            while(x%p[i]==0){
                x/=p[i];
            }
        }
    }
    if(x!=1) res = res/x*(x-1);
    return res%Mod;
}
int ex_gcd(int a,int b,int &x,int &y){
    if(b==0){
        x = 1;  y = 0;
        return a;
    }
    int g = ex_gcd(b,a%b,y,x);
    y -= a/b*x;
    return g;
}
int read(){
    int res = 0; char c;
    while((c=getchar())){
        if(c>='0'&&c<='9'){
            res = res+(c-'0');
            break;
        }
    }
    while((c=getchar())){
        if(c>='0'&&c<='9'){
            res *= 10;
            res = res+(c-'0');
        }else break;
    }
    return res;
}
int main(){
//    freopen("in.cpp","r",stdin);
//    freopen("out1","w",stdout);
    int T;
    init();
    T = read();
    while(T--){
        n = read(); m = read(); k = read();
        lyz = 0;
        for(int i=1;1LL*i*i<=(LL)(n);i++){
            if(n%i==0){
                yz[lyz++]=i;
                int j = n/i;
                if(i!=j) yz[lyz++]=j;
            }
        }
        memset(ok,0,sizeof(ok));
        while(k--){
            int u,v;
            u = read(); v = read();
            ok[u][v] = ok[v][u] = 1;
        }
        Mar B(m,m);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=m;j++){
                if(!ok[i][j]) {
                    B.a[j][i] = 1;
                }
            }
        }
        int ans = 0;
        for(int i=0;i<lyz;i++){
            int all = yz[i]; int sum = Euler(n/yz[i]);
            Mar Now = MarPow(B,all);
            int tmp = 0;
            for(int j=1;j<=m;j++){
                tmp = (tmp+Now.a[j][j])%Mod;
            }
            ans = (ans+(tmp*sum)%Mod)%Mod;
        }
//        printf("%d\n",ans);
//        printf("ans1 = %d\n",ans);
//         printf("now ans = "); cout<<ans/n<<endl;
        int xx,yy;
        ex_gcd(n,Mod,xx,yy);
        xx = (xx%Mod+Mod)%Mod;
//        xx = qpow(n,Mod-2);
        ans = (ans*xx)%Mod;
        printf("%d\n",ans);
    }
    return 0;
}
/**
5

2 4 1
1 2

1000000000 10 0

1000000000 10 3
1 2
3 4
5 5

9972 10 1
1 10

1234 1 0
*/
View Code

 

posted on 2017-11-26 20:42  icode-xiaohu  阅读(266)  评论(0编辑  收藏  举报