题意:
有m*n的(m是横坐标,n是纵坐标)格子,有k种颜色可以涂,其中有b个格子不能涂色,并且格子(x,y)与(x+1,y)的颜色不能相同。已知n,b,求当m最小为多少时,格子方案数mod100000007为r。
思路:
格子左边没有涂色格子的格子颜色有k种选择,左边有涂色格子的只有k-1种选择。
- m最小必须放下b个不能涂色的格子,m为maxx(不能涂色格子的最大横坐标)。找出在此区间左边无涂色格子的个数x1,有涂色格子的数目x2,判断ans1=kx1(k-1)x2%100000007是否为r。
- 1不成立的话,再增加1列,让m=maxx+1,找出在新的一列中左边无涂色格子的个数x3,有涂色格子的数目x4,判断ans2=ans1*kx3(k-1)x4%100000007是否为r。
- 2不成立的话,再增加的列中肯定全是左边有涂色格子的格子,再增加一列需要乘的方案数就是a=(k-1)n, 再增加x列就是乘以ax。假设再增加x列成立,所以ans2*ax=r(mod 100000007).
让b=r *inv(ans2)(ans2模100000007的逆元),c= 100000007。则ax=b(mod c)转化成了BSGS问题,求解x即可。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <map>
#include <bitset>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#define ll long long
using namespace std;
#define mod 100000007
struct point
{
long long x,y;
} p[569];
long long pow(ll a, ll b, ll p)
{
ll ans = 1;
while(b)
{
if(b & 1) ans = ans * a % p;
b >>= 1;
a = a * a % p;
}
return ans;
}
ll inv(ll a, ll p)
{
return pow(a, p-2, p);
}
map<ll, ll> mp;
ll BSGS(ll A, ll B, ll C)
{
mp.clear();
if(A % C == 0) return -2;
ll m = ceil(sqrt(C));
ll ans;
for(int i = 0; i <= m; i++)
{
if(i == 0)
{
ans = B % C;
mp[ans] = i;
continue;
}
ans = (ans * A) % C;
mp[ans] = i;
}
ll t = pow(A, m, C);
ans = t;
for(int i = 1; i <= m; i++)
{
if(i != 1)ans = ans * t % C;
if(mp.count(ans))
{
int ret = i * m % C - mp[ans] % C;
return (ret % C + C)%C;
}
}
return -2;
}
int main()
{
int t;
int ans1=1;
scanf("%d",&t);
long long n,k,b,r;
while(t--)
{
scanf("%lld%lld%lld%lld",&n,&k,&b,&r);
//ans1++;
long long maxx=0;
for(int i=0; i<b; i++)
{
scanf("%lld%lld",&p[i].x,&p[i].y);
maxx=max(maxx,p[i].x);
}
printf("Case %d: ",ans1);
ans1++;
long long x1,x2,ans;
ans=1;
x1=n;///zuobian无方格的个数
for(int i=0; i<b; i++)
{
if(p[i].x==1)
{
x1--;
}
if(p[i].x!=maxx)
{
x1++;
for(int j=0; j<b; j++)
{
if(p[j].x==(p[i].x+1)&&p[j].y==p[i].y)
{
x1--;
break;
}
}
}
}
//printf("%lld**\n",x1);
if(b)
{
ans=pow(k,x1,mod);
x2=n*maxx-x1-b;
ans=ans*pow(k-1,x2,mod)%mod;
if(ans==r)
{
printf("%lld\n",maxx);
continue;
}
long long x3,x4;
x3=0;
for(int i=0; i<b; i++)
{
if(p[i].x==maxx)
{
x3++;
}
}
x4=n-x3;
ans=(ans*pow(k,x3,mod))%mod;
ans=(ans*pow(k-1,x4,mod))%mod;
}
else
{
ans=pow(k,n,mod);
}
if(ans==r)
{
printf("%lld\n",maxx+1);
continue;
}
//n=n%(mod-1);
long long a=pow(k-1,n,mod);
long long b=inv(ans,mod)*r%mod;
long long c=mod;
ans=BSGS(a,b,c);
//printf("&&\n");
printf("%lld\n",ans+maxx+1);
}
return 0;
}
BSGS模版
long long pow(ll a, ll b, ll p)
{
ll ans = 1;
while(b)
{
if(b & 1) ans = ans * a % p;
b >>= 1;
a = a * a % p;
}
return ans;
}
ll inv(ll a, ll p)
{
return pow(a, p-2, p);
}
map<ll, ll> mp;
ll BSGS(ll A, ll B, ll C)
{
mp.clear();
if(A % C == 0) return -2;
ll m = ceil(sqrt(C));
ll ans;
for(int i = 0; i <= m; i++)
{
if(i == 0)
{
ans = B % C;
mp[ans] = i;
continue;
}
ans = (ans * A) % C;
mp[ans] = i;
}
ll t = pow(A, m, C);
ans = t;
for(int i = 1; i <= m; i++)
{
if(i != 1)ans = ans * t % C;
if(mp.count(ans))
{
int ret = i * m % C - mp[ans] % C;
return (ret % C + C)%C;
}
}
return -2;
}