1. 程式人生 > >[CF107D]Crime Management

[CF107D]Crime Management

題目大意:有一種長度為$n(n\leqslant 10^{18})$的字串,給定$m(m\leqslant10^3)$種限制,即字元$c$出現的次數為$cnt$,若一個字元有多種限制,則滿足任意一個即可,求這種字串有多少個,所有的$cnt$相乘小於等於 123,答案對 12345 取模。

題解:最多$6$個限制的$cnt\not=2$,狀態只需要記錄這些不為$1$的限制,可以把每個限制出現次數壓成一個數,構建矩陣,快速冪即可

卡點:

 

C++ Code:

#include <cstdio>
#include <vector>
#define maxn 1010
const int mod = 12345;
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;}
inline void up(int &a, int b) {if ((a += b) >= mod) a -= mod;}
inline long long pw(long long base, long long p) {
	base %= mod;
	long long res = 1;
	for (; p; p >>= 1, base = base * base % mod) if (p & 1) res = res * base % mod;
	return res;
}

int __sz = 1;
struct matrix {
	#define __M 150
	#define M __sz
	int s[__M][__M];
	inline matrix() {
		__builtin_memset(s, 0, sizeof s);
	}
	inline friend matrix operator * (const matrix &lhs, const matrix &rhs) {
		matrix res;
		for (register int i = 0; i < M; i++) {
			for (register int j = 0; j < M; j++) {
				long long tmp = 0;
				for (register int k = 0; k < M; k++) tmp += static_cast<long long> (lhs.s[i][k]) * rhs.s[k][j];
				res.s[i][j] = tmp % mod;
			}
		}
		return res;
	}
	#undef __M
	#undef M
} BASE, RES;

long long n;
int m;
int mp[300], ret[300], __name, prod[300];
int base[300];
std::vector<int> v[300];
inline int get(int x, int i) {return x / base[i - 1] % prod[i];}
inline bool check(int x) {
	for (int i = 1; i <= __name; i++) {
		bool find = false;
		int now = get(x, i);
		for (std::vector<int>::iterator it = v[i].begin(); it != v[i].end(); it++) if (now % *it == 0) {
			find = true;
			break;
		}
		if (!find) return false;
	}
	return true;
}

int main() {
	scanf("%lld%d", &n, &m);
	for (int i = 1, x, ch; i <= m; i++) {
		char __ch;
		scanf("%1s%d", &__ch, &x); ch = static_cast<int>(__ch);
		if (!mp[ch]) mp[ch] = ++__name, ret[__name] = ch, prod[__name] = 1;
		prod[mp[ch]] *= x;
		v[mp[ch]].push_back(x);
		__sz *= x;
	}
	base[0] = 1; for (int i = 1; i <= __name; i++) base[i] = base[i - 1] * prod[i];
	for (int i = 0; i < __sz; i++) {
		for (int j = 1; j <= __name; j++) {
			int now = get(i, j), nxt = (now + 1) % prod[j];
			up(BASE.s[i][i + (nxt - now) * base[j - 1]], 1);
		}
	}
	RES.s[0][0] = 1;
	for (; n; n >>= 1, BASE = BASE * BASE) if (n & 1) RES = RES * BASE;
	int ans = 0;
	for (int i = 0; i < __sz; i++) if (check(i)) up(ans, RES.s[0][i]);
	printf("%d\n", ans);
	return 0;
}