1. 程式人生 > >2018ACM-ICPC徐州賽區網路賽: A. Hard to prepare【遞推】

2018ACM-ICPC徐州賽區網路賽: A. Hard to prepare【遞推】

題目連結:傳送門

題意就不說了

思路:

一開始比賽的時候就是想   

k = 2^m

答案等於 k*((k-1)^(m-1)) 發現多了情況 因為是個環

然後換成 k*((k-2)^(m-1))*(k-2) 發現漏算了第一個和倒數第二個相同的情況

看了網上的其他題解,包括比賽時打的表明白了這其中的規律

那麼我們可以先算出第一個和倒數第二個不同的情況,而當他們相同的時候那麼最後一個就有(k-1)種情況,那麼就相當於整個長度被減去了2,得出的結果再加上去,可以由此進行dfs,因為給的n的值不大,時間複雜度是O(n),最後得出結果。

#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007
#define MAXN 1000005
using namespace std;
ll inv[MAXN];
ll k, n, m;
void init() {
	inv[1] = 2;
	for(int i = 2; i < MAXN; i++){
		inv[i] = inv[i-1] * 2LL % MOD;
	}
}
ll qpow(ll a, ll b){
	ll t = a, ans = 1;
	while(b) {
		if(b % 2){
			ans = ans * t % MOD;
		}
		t = t * t % MOD;
		b /= 2;
	}
	return ans;
}
ll cheak(ll len){
	if(len == 1){
		return k;
	}
	if(len == 2){
		return k * (k - 1) % MOD;
	}
	ll res = 0;
	res = k * qpow(k - 1, len - 2) % MOD * (k - 2) % MOD + cheak(len - 2) % MOD;
	return res;
}

int main() {
	int t;
	scanf("%d", &t);
	init();
	while(t--) {
		scanf("%lld%lld", &n, &m);
		k = inv[m] % MOD;
		printf("%lld\n", cheak(n) % MOD);
	}
	return 0;
}