The Patterns
问题描述:
输入
输入数据第一行为一个整数T(1 <= T <= 3333),表示有 T 组测试数据。
解题报告:
解题代码:
时间限制: 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:\n%d\n" , K++, (int) my_solve(n,m,p) );
}
return 0;
}