uva11916(数学题,模方程)

  题目的意思是有M*N列的格子,K种颜色,B个不能涂色的格子,涂色的约束条件是每一列相连的格子上不能是相同的颜色,然后总数Mod100000007的结果是等于R的,现在题目中告诉N,K,B,R,要求满足条件的最小M。

  解答:根据B个格子的坐标,可以求出最小的行minM,然后求对于minM*N的格子有多少种方案,然后再往外扩展一行,又有多少种方案,假设求得Mod完之后的结果为a,那么往后每添加一行,方案是当前的(k-1)^N次倍,即要求下面的方程解的最小值。

  ≡ 

  转化一下就是a^x ≡ b(Mod n)的模型

  

#include "stdio.h"
#include "string.h"
#include "math.h"
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;

#define MAXM 1
#define MAXN 1
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define Mem(a,b) memset(a,b,sizeof(a))
double pi = acos(-1.0);
double eps = 1e-6;

typedef struct{
	int f,t,w,next;
}Edge;
Edge edge[MAXM];
int head[MAXN];
int kNum;
typedef long long LL;

LL Mod = 100000007;

void addEdge(int f, int t, int w)
{
	edge[kNum].f = f;
	edge[kNum].t = t;
	edge[kNum].w = w;
	edge[kNum].next = head[f];
	head[f] = kNum ++;
}

LL N, K, R, B;
int T;
typedef struct{
	int x, y;
}BL;
BL bl[505];

bool comp(BL a, BL b){
	if( a.y == b.y )
		return a.x < b.x;
	return a.y < b.y;
}

LL pow_mod(LL a, LL m){
	if( m == 0 )
		return 1;
	LL ans = pow_mod(a, m/2) % Mod;
	ans = ans * ans % Mod;
	if( m % 2 )
		ans = ans * a % Mod;
	return ans;
}

void exgcd(LL a, LL b, LL &d, LL &x, LL &y){
	if( !b ){
		x = 1, y = 0;
		d = a;
	}
	else{
		exgcd(b, a % b, d, y, x);
		y -= x * ( a / b ) ;
	}
}
//求a在mod n下的逆
LL inv(LL a){
	LL x, y, d;
	exgcd(a, Mod, d, x, y);
	return d == 1 ? (x + Mod) % Mod : -1;
}
//求解a^x = b(mod n)
LL log_mod(LL a, LL b){
	LL m, v, e = 1;
	m = (LL)sqrt(Mod + 0.5);
	v = inv(pow_mod(a,m));
	map<LL, LL> x;
	x[1] = 0;
	for(int i = 1; i < m; i ++){
		e = e * a % Mod;
		if( !x.count(e) ) x[e] = i;
	}
	for(int i = 0; i < m; i ++){
		if( x.count(b) )
			return i * m + x[b];
		b = b * v % Mod;
	}
	return -1;
}

void solve(){
	int minM = 1;
	for(int i = 0; i < B; i ++){
		scanf("%d %d", &bl[i].x, &bl[i].y);
		if( minM < bl[i].x )
			minM = bl[i].x;
	}
	sort(bl, bl + B, comp);
	R = R % Mod;

	LL ans = 1, powK1 = N;
	for(int i = 0; i < B; i ++){
		if( bl[i].x == 1 )
			powK1 --;
		if( bl[i].x != minM ){
			if( i + 1 < B && bl[i+1].y == bl[i].y){
				if( bl[i].x + 1 != bl[i+1].x ){
					powK1 ++;
				}
			}
			else{
				powK1 ++;
			}
		}
	}
	ans = ans * pow_mod(K, powK1) % Mod;
	ans = ans * pow_mod(K-1, minM * N - powK1 - B) % Mod;
	if( ans == R ){
		printf("%d\n", minM);
		return;
	}
	powK1 = 0;
	for(int i = 0; i < B; i ++){
		if( bl[i].x == minM ){
			powK1 ++;
		}
	}
	ans = ans * pow_mod(K, powK1) % Mod;
	ans = ans * pow_mod(K-1, N - powK1) % Mod;
	if( ans == R ){
		printf("%d\n", minM + 1);
		return;
	}

//	LL x, y, d;
//	exgcd(ans, Mod, d, x, y);
	LL x = inv(ans) * R % Mod;
//	x = ( x * R + Mod * Mod ) % Mod;
	ans = pow_mod(K-1, N) % Mod;

	printf("%d\n", log_mod(ans, x) + minM + 1 );

}



int main()
{
//	freopen("d:\\test.txt", "r", stdin);
	while(cin>>T){
		for(int i = 0; i < T; i ++){
			cin>>N>>K>>B>>R;
			printf("Case %d: ", i + 1);
			solve();
		}
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值