小记: 上午盯着看了, 由于没注意看题目类型,所以不晓得是用动态规划,于是作死的从各方面想, 先是从数论方面,然后找规律,最后证实都不可行,期间 真的是很想很想 直接百度一下看看别人的思想, 但是想想,觉得这类题 就是一种分界线, 不能靠别人。 于是 再整理好思绪 认真分析, 然后 思路立马就出来了。。唉~ 天意啊, 以后认认真真做题, 坚决不搜题解,只在 代码有问题, 想和别人交流思想的情况下,再去搜题解,那样的效果最好。
思路:L位K进制,都是100 的数量级, 暴力肯定直接pass, 规律,寻不到(寻得到的 都是大神). 认真分析,对于每一位数, 如果不是最高位,那么都可以用0到k-1这k个数来填充这一位,对于填充的每一位,我们假定已经知道如果这一位填充它的话,那么好数会有f[i][j] 个(i表示第i位,j表示填的数),那么 我们将0-k-1这k个数的f[i][j]的值 全部相加起来最后得到的肯定是我们所要的答案(对于最高位为0,我们会另行判断,这里是假设),于是这里满足了dp的最优化原理,而对于第i位的数字,它的求值是无后效性的,因为结果只是相加,所以dp的无后效性也满足了,那么就可以用dp来做。
然后现在就是状态转移方程,f[i][j] = ∑f[i-1][r] (r != j±1 ,0<=r < k, i > 1)初始化f[1][j] = 1 (0<= j < k);
状态方程对最高位要特殊处理,因为最高位不能为0.
代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX_ = 101; const int M = 1000000007; int f[MAX_][MAX_]; int main() { int l, k; long long ans, n; while(cin >> k>> l) { if(l == 1){ cout<<k-1<<endl; continue; } memset(f,0,sizeof(f)); for(int j = 0; j < k; ++j) { f[1][j] = 1; } for(int i = 2; i < l; ++i) { for(int j = 0; j < k; ++j) { int cnt = 0; for(int r = 0; r < k; ++r) { if(r == j + 1 ||r == j - 1)continue; cnt = (cnt + f[i-1][r]) % M; } f[i][j] = cnt; } } int sum = 0; for(int j = 1; j < k; ++j) { int cnt = 0; for(int r = 0; r < k; ++r) { if(r == j + 1 ||r == j - 1)continue; cnt = (cnt + f[l-1][r]) % M; } sum = (sum + cnt)%M; } cout<< sum <<endl; } return 0; }