Crime Management CodeForces - 107D
问题描述: Zeyad 想要在埃及犯下N项罪行并且不想受到惩罚。有若干种类的罪行。例如,行贿是一项罪行但是当行贿重复两次的时候就不被认为是犯罪。因此,行贿在犯偶数次的时候不被当做犯罪。超速是一项罪行,但是当重复的次数是五的倍数的时候就不被认为是犯罪。
更特别的,现在已知有C个犯罪的条件。每个条件描述罪行的种类Ti和倍数Mi。如果Zeyad的犯Ti这罪名的次数是Mi的倍数,那么Zeyad就不会因此受到惩罚。有些罪名可能在条件中出现多次。那么只要满足至少一个条件Zeyad就不会受罚。当然如果Zeyad犯某种罪行的次数为0,他自然由于遵守法律而不会受罚。
现在Zeyad想知道他有多少种犯罪方式使得他恰好犯下n次罪却不会受到任何惩罚。
犯罪的顺序是有关系的。更正式的说,两个犯罪序列W1与W2被认为相同,当且仅当对于所有 1 ≤ i ≤ n,w1i = w2i成立。
输入格式:第一行有两个整数n,c 分别表示Zeyad想要犯罪的次数和他所知的条件的数目。紧接着是c个条件。共有26种罪名,分别用A-Z表示。每个条件包含一个大写字母表示罪名的类型和一个正整数表示倍数。所有条件中倍数的乘积不超过123。某些条件可以出现多次。当倍数是1时表示无论犯罪多少次都不会受到惩罚。显而易见,对于那些没有在条件中列出的罪名Zeyad不会考虑去犯它们因为这会不可避免地受到惩罚。
输出格式:输出一个非负整数,表示Zeyad恰好犯下n次罪却不会受到任何惩罚的犯罪方式数目模12345的值。
数据规模和约定: 0 ≤ n ≤ 1018, 0 ≤ c ≤ 1000
题解:此题最重要的一点是π(d)<=123。令p[i]为字母i所有d的乘积。p[i]<=123
f[i][a][b]…[z]:表示长度为i的字符串,‘A’个数 mod p[1] 等于a,‘B’个数 mod p[2] 等于b ……‘Z’个数 mod p[26] 等于z的情况总数。
因为π(d)<=123,所以每个n最多有123种状态。那么,把状态全部爆搜出来之后编号,就可以用一个123*123的矩阵来表示状态的转移。答案为矩阵的n次方。
坑点:n=0时一定有一种情况。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#define pb push_back
using namespace std;
typedef long long ll;
const int mod=12345;
const int N=1000+5;
const int L=123;
template <class T>
inline void getin(T&num){
char c;bool flag=0;num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=