UVA - 11916 Emoogle Grid

题目

好久没有1Y了呢,而且还是数学题。

思路:

如果没有block,那么除了第一行是pow(k, m)之外其余的每一层都是pow(k - 1, m)

a = pow(k, m)t = pow(k - 1, m)

相当于求一个模方程a * t ^ x \equiv ans(mod (1e8 + 7))

两边乘以inv(a)之后求一个离散对数即可。

如果之前一层有block,那么对应这一层的位置就可以放k个(如果这个位置没有block的话),其他位置放k - 1个。

把有block的行存入set,每行每行分情况进行计算。

(码力不精,代码特判较多。)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

typedef vector<int> vi;
typedef vector<vi> vii;
typedef vector<ll> vl;
typedef vector<vl> vll;
typedef vector<double> vd;
typedef vector<vd> vdd;
typedef pair<int, int> ii;

const ll MOD = 1e8 + 7;
const double eps = 1e-6;
const ll INF = 0x3f3f3f3f;
const double PI = acos(-1.0);

ll n, m, k, b, ans;

set<ll> rec;
map<ll, set<ll> > mp;

ll qp(ll a, ll b){
	if(!b)
		return 1 % MOD;
	if(b & 1)
		return a * qp((a * a) % MOD, b >> 1) % MOD;
	return qp((a * a) % MOD, b >> 1);
}

ll inv(ll x){
	return qp(x, MOD - 2);
}

ll cal(ll a, ll b){
	ll m = sqrt(MOD + 0.5);
	map<ll, ll> cap;
	for(ll i = 0; i < m; i++){
		ll cur = qp(a, i);
		if(!cap.count(cur))
			cap[cur] = i;
	}
	for(ll i = 0; i <= m; i++){
		if(cap.count(b))
			return cap[b] + i * m;
		b = (b * inv(qp(a, m))) % MOD;
	}
	return -1;
}

int main(void)
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << setprecision(10) << fixed;
	int times;
	cin >> times;
	for(int cas = 1; cas <= times; cas++){
		cin >> m >> k >> b >> ans;
		rec.clear();
		mp.clear();
		for(int i = 0; i < b; i++){
			ll x, y;
			cin >> x >> y;
			rec.insert(x);
			mp[x].insert(y);
		}
		ll res = 1;
		ll t = qp(k - 1, m);
		n = 1;
		for(auto u = rec.begin(); u != rec.end(); ++u){
			ll i = *u;
			if(u == rec.begin()){
				if(i > 1)
					res = (res * qp(k, m)) % MOD;
				if(i - 2 >= 0)
					res = (res * qp(t, i - 2)) % MOD;
				res = (res * qp(k - (i > 1), m - mp[i].size())) % MOD;
			}
			else{
				auto pre = u;
				pre--;
				ll j = *pre;
				if(j + 1 != i){
					res = (res * qp(k - 1, m - mp[j].size())) % MOD;
					res = (res * qp(k, mp[j].size())) % MOD;
				}
				if(i - j - 2 >= 0)
					res = (res * qp(t, i - j - 2)) % MOD;
				if(j + 1 != i)
					res = (res * qp(k - 1, m - mp[i].size())) % MOD;
				else{
					ll num = mp[i].size();
					for(auto v = mp[j].begin(); v != mp[j].end(); ++v)
						if(!mp[i].count(*v)){
							res = (res * k) % MOD;
							num++;
						}
					res = (res * qp(k - 1, m - num)) % MOD;
				}
			}
			n = i;
		}
		cout << "Case " << cas << ": ";
		if(rec.size()){
			if(res == ans){
				cout << n << endl;
				continue;
			}
			res = (res * qp(k, mp[n].size())) % MOD;
			res = (res * qp(k - 1, m - mp[n].size())) % MOD;
			n++;
			if(res == ans){
				cout << n << endl;
				continue;
			}
		}
		else
			res = qp(k, m);
		res = cal(t, (ans * inv(res)) % MOD);
		cout << n + res << endl;
	}
	cerr << "execute time: " << (double)clock() / CLOCKS_PER_SEC << endl;
	return 0;
}

 

未来可期。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值