UVA11916 Emoogle Grid

来源:互联网 发布:数据库权限管理 编辑:程序博客网 时间:2024/06/06 01:11

题目链接:点我


题意:

给你一个m * n的矩阵, 矩阵上有 B 个点不可填充,剩下的点填 K 种 颜色,现在给你矩阵的 N ,和 R ,R代表这个矩阵用这 K 种颜色填充共有多少种不同的方案.让你求矩阵的 N .

思路:

核心难点是大步小步算法(Baby Steps Giant Steps).首先我们先找出矩阵不能填的点的最大纵坐标maxy,然后判断以maxy 为 N 是否符合条件,如果不符合我们再判断以 maxy + 1 为 N ,判断是否符合条件,如果还是不符合,那么接下来我们算出此时以 maxy + 1 为 N 的 矩阵填充共有多少种不同的方案,然后我们知道,在 maxy + 1 的基础上 N 没增加 1 ,我们的填充方案数就应该乘以 (K1)M,那么接下来就是我们用BSGS算法求解的过程.

BSGS: 先看一个式子 xy ≡ z (mod p),p是质数,现在只知道x和 z 和 p , 要求 y . 大步小步算法(BSGS,Baby Steps Giant Steps)就是解决这个问题的,当然还有扩展的大步小步算法可以解决 p 不是素数的情况.

首先我们设 m = p, 然后我们设 y = i * m + j; 那么 xy = xmi+j, 其中 0 i, j < m,那么我们只需要枚举 i, 余数复杂度降为 p. 于是原式可以写成: xj = xim * z,于是我们找到xm的逆元,然后枚举即可,

代码:

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#include<cmath>#include<map>#include<set>using namespace std;typedef long long LL;const int mod = 1e8 + 7;set<pair<int, int> > best;int x[510],y[510];LL qpow(LL x,LL n){    LL ans = 1;    while(n){        if(n & 1) ans = ans * x % mod;        x = x * x % mod;        n >>= 1;    }    return ans;}void  exgcd(LL a,LL b, LL &d, LL &x, LL  &y){//扩展欧几里得算法求逆元,    if(!b){x = 1; y = 0;d = a; return ;}    exgcd(b, a %b, d, y, x);     y-= a/b * x;}LL inv(LL a){    LL x, y,d;    exgcd(a,mod,d,x,y);    return d == 1 ? (x + mod ) % mod : -1;}int BSGS(LL x,LL r){    LL m =(LL)ceil(sqrt((double)mod+0.5));  //  LL v = qpow(qpow(x,mod-2),m);    LL v = inv(qpow(x,m));//经验证,两种方法都可以求得正确的逆元    map<LL,LL> q;    map<LL,bool> vis;    LL k = 1;    vis[k] = 1;    q[k] = 0;    for(int i = 1; i < m; ++i){//枚举x 的次方        k = k * x % mod;        if(vis[k] == 0){            vis[k] = 1;            q[k] = i;        }    }for(int i = 0; i< m; ++i){        if(vis[r]){//如果左右两边都已经出现了,那么说明找到解.            int ans = i * m +q[r];            return ans;        }        r =r * v % mod;//每次乘以逆元,即是在算我们上述的 x ^(- i* m) * z;    }    return -1;}int main(){    int t;    scanf("%d", &t);    int kase = 0;    while(t--){        LL b, n, k, r,num;        int maxx;        scanf("%I64d %I64d %I64d %I64d", &n, &k, &b, &r);        maxx = 1;num = 0;best.clear();        for(int  i = 1; i  <= b ; ++i){            scanf("%I64d %I64d", &x[i], &y[i]);            maxx= max(maxx,x[i]);//找到最大的x,            best.insert(make_pair(x[i],y[i]));        }for(int i= 1; i <= b; ++i)            if(x[i] != maxx && !best.count(make_pair(x[i]+1,y[i])))                ++num;        for(int  i = 1; i <= b;++i)            if(x[i] == 1)                --num;        num += n;        LL sum = (qpow(k,num) * qpow(k - 1, maxx * n - b - num) ) % mod;        if (sum == r) {//判断是否符合条件,            printf("Case %d: %d\n",++kase, maxx);            continue;        }num = 0;        for(int i = 1; i <= b; ++i)            if(x[i] == maxx)                ++num;        ++maxx;        sum = sum * qpow(k-1,n-num) % mod;        sum = sum * qpow(k,num) % mod;        if (sum == r){            printf("Case %d: %d\n",++kase, maxx );            continue;        }LL x = qpow(k-1,n);        r = r *inv(sum) % mod;       int ans = maxx + BSGS(x,r);       printf("Case %d: %d\n",++kase,ans);    }return 0;}
原创粉丝点击