USACO19JAN Cow Poetry

题意

给定\(N\leq1000\)个单词,每个单词有两个属性:长度\(s_i\),音节\(c_i\)

奶牛Bessie想要创作一首有\(M\leq 10^5\)行的诗歌,其中,对于每一行规定其韵脚为\(C\)\(C\)为一大写字母),其长度为\(K\leq 1000\)

也就是说,组成第\(i\)行的单词的长度之和为\(K\),并且对于所有韵脚为\(C\)的行,其最后一个单词的音节都是相同的(不同韵脚的行的音节也有可能相同)

请求出Bessie可能创作的不同的诗歌的数目取模\(10^9 +7\)


解法

观察到韵脚最多只有\(26\)种,我们可以发现最终复杂度与\(M\)无关

\(f[i]\)为最后一个单词音节为\(i\),总长度为\(K\)的段的方案数,\(cnt[i]\)为韵脚为\(i\)的行数

那么最后的答案即为\(\prod (\sum f[j]^{cnt[i]})\)

接下来我们求\(f\)数组

我们枚举最后一个单词的音节\(c\),在确定音节以后枚举对应的单词\(i\)

\(g[i]\)为长度为\(i\)的段的组合方案数

那么\(f[c]=\sum g[K-s_i]\times[c_i =c]\)

\(g\)数组背包预处理即可:由于这里的组合方案是有序的,所以我们外层枚举长度,内层枚举物品(否则求出的组合方案是无序的)


代码

#include <cstdio>

using namespace std;

const int MAX_N = 5e3 + 10;
const int mod = 1e9 + 7;

int N, M, K, top;

int a[30], t[30];
int s[MAX_N], c[MAX_N], f[MAX_N], g[MAX_N], h[MAX_N];

char ch[10];

inline void add(int& x, int y) { x = (x + y) % mod; }
inline void mul(int& x, int y) { x = 1LL * x * y % mod; }

inline int qpow(int x, int y) {
	int res = 1;
	for (; y; mul(x, x), y >>= 1)
		if (y & 1)  mul(res, x);
	return res;	
}

int main() {
	
	scanf("%d%d%d", &N, &M, &K);
	
	for (int i = 1; i <= N; ++i)  scanf("%d%d", s + i, c + i);
	
	for (int i = 1; i <= M; ++i) {
		scanf("%s", ch);
		a[ch[0] - 'A' + 1]++;
	}
	
	for (int i = 1; i <= 26; ++i)  
		if (a[i])  t[++top] = a[i];
	
	g[0] = 1;
	for (int i = 1; i <= K; ++i)
		for (int j = 1; j <= N; ++j)
			if (i >= s[j])  add(g[i], g[i - s[j]]); 
	
	for (int i = 1; i <= N; ++i)
		for (int j = 1; j <= N; ++j) {
			if (c[j] ^ i)  continue;
			add(f[i], g[K - s[j]]);
		}
	
	int ans = 1;
	for (int i = 1; i <= top; ++i)
		for (int j = 1; j <= N; ++j)  
			add(h[i], qpow(f[j], t[i]));			
	
	for (int i = 1; i <= top; ++i)  mul(ans, h[i]);
	
		
	printf("%d\n", ans);
		
	return 0;		
}
posted @ 2019-10-10 21:26  四季夏目天下第一  阅读(117)  评论(1编辑  收藏  举报