UVA---11916:Emoogle Grid 【BSGS】

题意:

给 m * n 的矩阵涂色,要求上下相邻的格子不能涂一样的颜色,其中有 b 个格子不能涂色,给出涂色的方案数 r 和 列数 n,求这个矩阵的行数 m

分析:

不难发现,每一列被不能涂色的格子分成了几块,那么就有几个格子能涂 k 种颜色,剩余的只能涂 k-1 种颜色,设 m = max(不能涂色的 x ),m 和 m+1以后的情况是不一样的,因为 m+1 后有的列会多出一块,特判一下,用BSGS求解即可

疑点:

当 b = 0 时,有:k^n*(k-1)^{n*x-n}=r~~(mod~~p),BSGS求解 x 即可,但会WA,必须要特判 K^n = r 时,最后答案为 1。这个特判和求扩展BSGS时的特判类似,必须特判一下 K^n = r,m 和 m+1 也要特判,因为K的指数会不一样。我始终不能理解这个为什么要特判,望路过的大佬指点迷津

代码:


#include <map>
#include <set>
#include <cmath>
#include <cstdio>
#include <iostream>
#define fi first
#define se second
#define mk make_pair
#define LL long long
#define pii pair<LL,LL>
using namespace std;
const int mod = 100000007;
LL n,k,b,r,a,d;
LL qpow(LL a,LL x)
{
    LL res = 1;
    while(x)
    {
        if(x&1) res = res * a % mod;
        a = a * a % mod;
        x >>= 1;
    }
    return res;
}
LL Bsgs()
{
    LL t = ceil(sqrt(mod*1.0));
    map<LL,LL> p;
    for(int j = 1; j <= t ; ++j)
    {
        r = r * a % mod;
        p[r] = j;
    }
    LL v = qpow(a,t);
    for(int i = 1; i <= t+1; ++i)
    {
        d = d * v % mod;
        if(p[d])
            return i * t - p[d];
    }
    return -1;
}
int main()
{
    int t; scanf("%d",&t);
    for(int cases = 1; cases <= t; ++cases)
    {
        scanf("%lld %lld %lld %lld",&n,&k,&b,&r);
        set<pii> s;
        LL x,y,M = -1;
        for(int i = 0; i < b; ++i)
        {
            scanf("%lld %lld",&x,&y);
            M = max(M,x);
            s.insert(mk(x,y));
        }
        printf("Case %d: ",cases);
        set<pii>::iterator it = s.begin();
        if(b>0)
        {
            LL sum = n,num = 0;             //块数、x = M的数量
            for(; it != s.end(); ++it)
            {
                pii p = *it;
                if(p.fi != M && !s.count(mk(p.fi+1,p.se))) sum++;
                if(p.fi == 1) sum--;
                else if(p.fi == M ) num++;
            }
            LL rr = qpow(k,sum) * qpow(k-1,n*M-sum-b) % mod;
            if(rr == r)                      //特判 M
            {
                printf("%lld\n",M);
                continue;
            }
            M = M + 1;
            rr = rr * qpow(k,num) % mod;
            rr = rr * qpow(k-1,n-num) % mod;
            if(rr == r)                      //特判 M + 1
            {
                printf("%lld\n",M);
                continue;
            }
            a = qpow(k-1,n);
            d = rr;
            printf("%lld\n",M+Bsgs());
        }
        else
        {
            LL rr = qpow(k,n);
            if(rr == r) printf("1\n");      //特判
            else
            {
                d = rr;
                r = r * qpow(k-1,n) % mod;
                a = qpow(k-1,n);
                printf("%lld\n",Bsgs());
            }
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值