UVA 11916 Emoogle Grid(模指数方程)

来源:互联网 发布:《梦里花落知多少》txt 编辑:程序博客网 时间:2024/06/01 07:43

题意:用k种不同颜色给m*n方格涂色。其中有b个点不用涂色,给出这b个点的位置。满足上下相邻的两个位置不能涂相同颜色。
已知列数n和涂色总方案r(已经对mod取模)。求最小的行数m
解法:
1.对于m*n列方格,k中不同颜色涂色,且上下不能涂相同颜色,共:
(k*(k-1)^(m-1))^n中染色方案数
2.有若干格子不能染色,则可以跳过格子进行类似统计。得到前m1行的染色数目和第m+1行的染色数目之和cnt(m1是不用涂色的格子中最大的行数),以后每增加一行cnt*=(k-1)^n,令(k-1)^n为p,则cnt*p^(ans-m-1)=r (mod),p^(ans-m-1)=r *inv(cnt)(mod),即解一个模指数方程,使用Baby-Step算法。

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<map>#include<vector>#include<queue>#include<stack>#include<math.h>#include<set>#define MP make_pair#define ll long longusing namespace std;const ll mod = 100000007 ;const ll maxn = 500+10 ;ll t,n,k,b,r,m,x[maxn],y[maxn];set<pair<ll,ll> > best;void gcd(ll a,ll b,ll &d,ll &x,ll&y){    if(!b) { d=a;x=1;y=0; }    else { gcd(b,a%b,d,y,x); y-=(x*(a/b)); }}ll inv(ll a){    ll d,x,y;    gcd(a,mod,d,x,y);    return d==1?(x+mod)%mod:-1;}ll mul_mod(ll a,ll b){    return ((a%mod)*(b%mod))%mod;}ll pow_mod(ll a,ll b){    ll ans=1;    while(b){        if(b&1) ans=mul_mod(ans,a),b--;        a=mul_mod(a,a),b>>=1;    }    return ans;}//统计不变部分的涂色种类数ll Count(){    ll c=0;    //统计不能涂色格子下的可涂k种颜色的格子数    for(ll i=0;i<b;i++){        if(x[i]!=m&&!best.count(MP(x[i]+1,y[i]))) c++;    }    //统计第一行的可涂k种颜色的格子数    c+=n;    for(ll i=0;i<b;i++) if(x[i]==1) c--;    return mul_mod(pow_mod(k,c),pow_mod(k-1,m*n-b-c));}ll log_mod(ll a,ll b){    ll m,v,e=1,i;    m=(ll)sqrt(mod+0.5);    v=inv(pow_mod(a,m));    map<ll,ll> x;    x[1]=0;    for(i=1;i<m;i++){        e=mul_mod(e,a);        if(!x.count(e)) x[e]=i;    }    for(i=0;i<m;i++){        if(x.count(b)) return i*m+x[b];        b=mul_mod(b,v);    }    return -1;}ll doit(){    ll cnt=Count();    if(cnt==r) return m;    ll c=0;    for(ll i=0;i<b;i++)        if(x[i]==m) c++;    m++;    cnt=mul_mod(cnt,pow_mod(k,c));    cnt=mul_mod(cnt,pow_mod(k-1,n-c));    if(cnt==r) return m;    return log_mod(pow_mod(k-1,n),mul_mod(r,inv(cnt)))+m;}int main(){    //freopen("a.txt","r",stdin);    scanf("%lld",&t);    for(ll cas=1;cas<=t;cas++){        scanf("%lld%lld%lld%lld",&n,&k,&b,&r);        best.clear();        m=1;        for(ll i=0;i<b;i++){            scanf("%lld%lld",&x[i],&y[i]);            if(x[i]>m) m=x[i];            best.insert(MP(x[i],y[i]));        }        printf("Case %lld: %lld\n",cas,doit());    }    return 0;}
0 0
原创粉丝点击