时间限制: 5s 内存限制: 65536K
问题描述:
对于一个1到n的全排列Q,我们定义Q对应的字符串SQ,其中

例如对于n=5,Q=32154, SQ=DDUD。
本任务为给定一个仅包含字符’U’与’D’长度为m的模式串P以及一个正整数n,求解1到n的任意全排列中模式串出现次数的期望值。例如某个SQ=UUU,P=UU,则P出现次数为2次。
例如n=3,P=U,则1到n的所有全排列方案对应的模式串P出现次数分别为
则1到n的任意全排列中模式串出现次数的期望值

为了避免浮点数精度误差,请输出
,其中mod为取模操作,具体定义以及运算规则参见:链接地址

输入
输入数据第一行为一个整数T(1 <= T <= 3333),表示有 T 组测试数据。
下面T组数据,每组数据第一行包含2个正整数n, m,接下来一行包含一个字符串P(仅包含字符’U’与’D’)
数据规模:1 <= m <= 1000 m<n<=1000000
输出
对于第k组数据,第一行输出Case #k:,第二行输出
。

样例输入
5
4 3
UUU
4 2
UU
10 8
UUUUDDDD
2 1
U
2 1
D
样例输出
Case #1:
1
Case #2:
8
Case #3:
1400
Case #4:
1
Case #5:
1
解题报告:
首先计算n=m+1的情况下,1到n的所有全排列中能匹配P的次数。令其为A,则此时期望为

令事件X_i表示在某个排列Q的第i个元素开始,之后的m+1个元素符合模式串P。则

根据期望的线性

则

因此只需要求解得到A即可得到答案。
计算A采用动态规划算法
f[i,j] 表示前 i 个数字,最后一个数字所在前i个数字中的排名为j (排名从1开始)
则有
f[1,1] = 1
for i = 2..m + 1
for j = 1..i
if p[i-2] == 'U'
f[j]= f[i-1][j-1]+f[i-1][j-2]+…+f[i-1][1];
else
f[j]= f[i-1][j]+f[i-1][j+1]…f[i-1][i-1];
时间复杂度为O(m^3)
而通过部分和优化可以优化到O(m^2)
#include <functional> #include <algorithm> #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <numeric> #include <cstring> #include <climits> #include <cassert> #include <cstdio> #include <string> #include <vector> #include <bitset> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <list> #include <set> #include <map> using namespace std; typedef long long LL; const int P = (int)1e9 + 7 ; const int MAXN = 1234; int count( char a[], char b[]) { int ret = 0; int rem = strlen(a); int m = strlen(b); for(int i = 0; a; ++ i, -- rem) if(rem >= m){ bool ok = 1; for(int j = 0; b[j]; ++ j) { if(a[i+j] != b[j]) { ok = 0; break; } } if(ok) ret ++ ; } return ret; } int a[ MAXN ]; LL f[ MAXN ][ MAXN ] , g[ MAXN ][ MAXN ]; void inc( LL &a, LL b) { b%=P; if(b<0) b+=P; a += b; if(a>=P) a-= P; } LL dp( int m, char p[]){ f[1][1] = 1 ; g[1][0] = 0;g[1][1] = 1; for(int i = 2; i <= m + 1; ++ i) { g[0]=0; for(int j = 1; j <= i; ++ j) { if( p[i-2] == 'U') { f[j] = g[i-1][j-1]; }else { f[j] = ((g[i-1][i-1] - g[i-1][j-1])%P+P)%P; } g[j] = (g[j-1] + f[j])%P; } } LL ans = 0; for(int i = 1; i <= m + 1; ++ i) inc( ans , f[m+1]); return ans; } LL bf(int n, int m, char p[]){ char s[MAXN]; s[n-1]=0; LL ans = 0; for(int i = 0; i < n; ++ i) a=i; do{ for(int i = 0; i < n-1 ; ++ i) s = (a<a[i+1]?'U':'D'); ans += count( s , p ) ; }while(std::next_permutation(a,a+n)); return ans; } LL bf_solve( int n, int m, char p[]) { LL _one = bf(m+1,m,p) * (n-m); for(int i = m+2; i <= n; ++ i) _one *= i ; return _one; } LL my_solve( int n, int m, char p[]) { LL _one = dp(m,p) * ((LL)n-m)%P; for(int i = m+2; i <= n; ++ i) _one =_one* i%P ; return _one; } void bf_check(){ int n, m; char p[MAXN]; for(n = 2; n <= 9; ++ n) { for(m = 1; m < n; ++ m) { p[m]=0; for(int s = 0; s < (1<<m); ++ s) { for(int i = 0; i < m; ++ i) p=(s&(1<<i))?'U':'D'; cout << n <<" " << m <<" " << p << endl; LL _a = bf( n, m, p ) ; LL _b = my_solve(n,m,p); cout << _a << endl; if(_a == _b) { static int cas = 0; ++ cas; cout <<"correct @" << cas << endl; }else { cout << "error!" << endl; return; } } } } } char p[ MAXN ]; int n, m ; int main() { //bf_check(); int T; int K = 1; cin >> T; while(T -- ) { scanf("%d%d%s", &n, &m, p); printf ("Case #%d: %d " , K++, (int) my_solve(n,m,p) ); } return 0; }