UVa11916

来源:互联网 发布:vb 修改批处理 编辑:程序博客网 时间:2024/05/22 15:54

题目链接

简介:
有这样一个题目:给定一个M*N的网格涂上K种颜色,其中B个格子不能涂色,其他每个格子涂一种颜色,同一列中的上下两个相邻格子不能涂相同颜色
给出M,N,B个格子的位置,求出涂色方案R%100000007

这道题是上述问题的逆问题:给出N,K,R,B个格子的位置,
求出最小的M

分析:
虽然M(行数)是未知的,但是我们可以知道ta的最小值:
M=max{不能涂色的格子的行编号}
因此可以把整个网格分成两部分:不可变部分,可变部分
这里写图片描述
我们一列一列的进行涂色
如果一个格子上一个位置不能涂色,那么ta的颜色就有K种选择
其余的格子都只有K-1种选择

假设不变部分以及可变部分的第一行可行的涂色方案有cnt种
(cnt的求解要稍微麻烦一点)
那么每增加一行,涂色方案都会乘P=(K-1)^N
这样我们就得到一个模方程:

cnt*P^M=R

稍微变形得到:

P^M=R*cnt^-1

直接上bsgs求解即可

tip

B=0的时候需要特殊求解
时刻判断cnt是不是已经等于r了

交上去是T,拍也拍不起来(数据不好造)

//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<map>#include<set>#include<cmath>#define ll long longusing namespace std;const ll mod=100000007;map<ll,int> mp;int n,m,k,r,b,x[1000],y[1000];set<pair<int,int> > po;              //方便判断ll KSM(ll x,ll y){    ll t=1;    x%=mod;    while (y)    {        if (y&1)            t=(t%mod*x%mod)%mod;        y>>=1;        x=(x%mod*x%mod)%mod;    }    return t%mod;}int bsgs(ll x,ll z)                  //x^y=z{    x%=mod; z%=mod;    if (x==0&&z==0) return 1;    if (x==0) return -1;    mp.clear();    ll now=1;    ll m=(ll)ceil(sqrt((double)mod));    mp[1]=m+1;    for (int i=1;i<m;i++)    {        now=(now%mod*x%mod)%mod;        if (!mp[now]) mp[now]=i;     //x^i=now    }    ll inv=1,tmp=KSM(x,mod-m-1);    for (int k=0;k<m;k++)    {        int i=mp[(z*inv)%mod];       //z*x^-km        if (i)        {            if (i==m+1) i=0;            return k*m+i;        }        inv=(inv%mod*tmp%mod)%mod;     }    return -1;}ll count(){    int i,j;    int c1=0;    for (int i=1;i<=b;i++)        if (x[i]!=m&&!po.count(make_pair(x[i]+1,y[i])))   //计算不可涂色的方格下面有多少不受限制的方格             c1++;                                         //其中不包含行数大于m的不受限制方格     c1+=n;                                                //第一行都有k种涂法       for (int i=1;i<=b;i++)        if (x[i]==1) c1--;                                //去除不能涂色的方块    int c2=n*m-c1-b;                                      //有k-1种涂色方法的方格    //a=k^c1 * (k-1)^c2 方案数     ll a=(KSM((ll)k,(ll)c1) * KSM((ll)(k-1),(ll)c2))%mod;     return a;}int doit(){    ll cnt=count();    if (cnt==r) return m;               int c=0;    for (int i=1;i<=b;i++)        if (x[i]==m) c++;                                   //可变部分中不受限制的方格数     cnt=(cnt * KSM((ll)k,(ll)c))%mod;    cnt=(cnt * KSM((ll)(k-1),(ll)(n-c)))%mod;    if (cnt==r) return m+1;    m++;    ll P=KSM((ll)(k-1),(ll)n);    ll rr=(r*1LL*KSM(cnt,mod-2))%mod;    return bsgs(P,rr)+m;}int main(){    int T;    scanf("%d",&T);    for (int cas=1;cas<=T;cas++)    {        m=0;        scanf("%d%d%d%d",&n,&k,&b,&r);        for (int i=1;i<=b;i++)        {            scanf("%d%d",&x[i],&y[i]);            po.insert(make_pair(x[i],y[i]));            if (x[i]>m) m=x[i];        }        if (b==0)        {            ll cnt=KSM((ll)k,(ll)n);            if (cnt==r) m=1;            else            {                ll P=KSM((ll)(k-1),(ll)n);                ll rr=(r*1LL*KSM(cnt,mod-2))%mod;                m=bsgs(P,rr)+1;            }            printf("Case %d: %d\n",cas,m);              }        else printf("Case %d: %d\n",cas,doit());        }    return 0;}
原创粉丝点击