1. 程式人生 > >UVA - 11916 Emoogle Grid (組合計數+離散對數)

UVA - 11916 Emoogle Grid (組合計數+離散對數)

直接 ongl 討論 其中 case print span 有一個 ++i

假如有這樣一道題目:要給一個M行N列的網格塗上K種顏色,其中有B個格子不用塗色,其他每個格子塗一種顏色,同一列中的上下兩個相鄰格子不能塗相同顏色。給出M,N,K和B個格子的位置,求出塗色方案總數除以1e8+7的結果R。

本題的任務和這個相反:已知N,K,R和B個格子的位置,求最小可能的M。

藍書(大白)上的例題,設xm為不能塗色的格子的最大x值,則分三種情況討論:M=xm,M=xm+1,M>xm+1。前兩種用組合公式直接算,第三種可設前xm+1行的格子塗色方法有n種,由於每增加一行,總塗色方案數增加p=(k-1)^N,於是有n*p^(M-xm-1)=R,用BSGS算法求出M-xm-1的值即可得到答案。

中間有一個連乘少取了一次模爆了longlong,差點debug到自閉..

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 const ll N=500+10;
 6 const ll mod=1e8+7;
 7 struct P {
 8     ll x,y;
 9     bool operator<(const P& b)const {return x!=b.x?x<b.x:y<b.y;}
10 };
11 ll n,k,b,r,ka;
12 ll x[N],y[N],xm,all; 13 set<P> st; 14 15 ll Pow(ll a,ll b) { 16 ll ret=1; 17 for(; b; b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod; 18 return ret; 19 } 20 ll inv(ll a) {return Pow(a,mod-2);} 21 ll Log(ll a,ll b) { 22 ll m=sqrt(mod+0.5),v=inv(Pow(a,m)); 23 map<ll,ll> mp;
24 for(ll i=0,e=1; i<m; ++i,e=e*a%mod)if(!mp.count(e))mp[e]=i; 25 for(ll i=0; i<m; ++i,b=b*v%mod)if(mp.count(b))return i*m+mp[b]; 26 return -1; 27 } 28 29 ll solve() { 30 ll ans=Pow(k,all)*Pow(k-1,n*xm-all-b)%mod; 31 if(ans==r)return xm; 32 ll cnt=0; 33 for(ll i=0; i<b; ++i)if(x[i]==xm)++cnt; 34 ans=ans*Pow(k,cnt)%mod*Pow(k-1,n-cnt)%mod; 35 if(ans==r)return xm+1; 36 return xm+1+Log(Pow(k-1,n),r*inv(ans)%mod); 37 } 38 39 int main() { 40 ll T; 41 scanf("%lld",&T); 42 while(T--) { 43 printf("Case %lld: ",++ka); 44 xm=1; 45 st.clear(); 46 scanf("%lld%lld%lld%lld",&n,&k,&b,&r); 47 all=n; 48 for(ll i=0; i<b; ++i) { 49 scanf("%lld%lld",&x[i],&y[i]); 50 xm=max(xm,x[i]); 51 st.insert({x[i],y[i]}); 52 if(x[i]==1)all--; 53 } 54 for(ll i=0; i<b; ++i) { 55 if(x[i]!=xm&&!st.count({x[i]+1,y[i]}))all++; 56 } 57 printf("%lld\n",solve()); 58 } 59 return 0; 60 }

UVA - 11916 Emoogle Grid (組合計數+離散對數)