题目描述
给定两个正整数 t,N t , N 分别表示本次问答竞赛的时间和问题的数目,对于每个问题以一个问号作为结尾,后面是其的答案,问在给定的 t t 时间内最大期望能答对多少题?
数据范围
The first line contains two integers
(1<=t<=100,1<=N<=100000)
(
1
<=
t
<=
100
,
1
<=
N
<=
100000
)
the duration of the quiz and the number of questions. Each of the following
N
N
lines contains a question, which is a space-separated list of words terminated by a question mark; and an answer, which is a single word. Each word is a sequence of non-space ASCII printable characters, between the ASCII values of ‘!’ and ‘∼’. Only the last word of a question has a question mark (‘?’). You can assume that no question is a prefix of another and that punctuation marks are part of a word. Words spelled with different upper/lower case are assumed to be different.
It is guaranteed that the total number of word characters is at most 100000。
分析
看到单词的问题其实就应该直接想到字典树,不过这个是以一个单词作为一个节点来处理,对于每个单词维护两个map,一个记录其后继,一个记录当前这一位后继的个数,这样就可以dp来做啦。
#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
char ch = getchar();
int x = 0 , f = 1 ;
while( !isdigit( ch ) )
if( ch == '-' ) f = -1 , ch = getchar();
else ch = getchar();
while( isdigit( ch ) )
x = (ch - '0') + x * 10 , ch = getchar();
return x * f;
}
typedef long long ll;
const ll p1 = 197 , p2 = 179 , mod1 = 1e9 + 7 , mod2 = 1e9 + 9;
#define PII pair<ll,ll>
#define fr first
#define se second
string s;
PII gethash(){
PII res( 0 , 0 );
for( int i = 0 ; s[i] ; ++i ){
( res.fr = res.fr * p1 + s[i] ) %= mod1;
( res.se = res.se * p2 + s[i] ) %= mod2;
}
return res;
}
const int maxn = 100000 + 30;
struct Tire{
map<PII , int> mp;
map<PII , int> cnt;
void cls(){
mp.clear();
}
} tree[maxn];
int cnt[maxn] , N , T , tot;
vector<int> g[maxn];
#define PB push_back
void build( int x ){
int rt = 0 ; g[x].PB( rt ); cnt[rt]++;
while( cin >> s ){
PII t = gethash();
if( tree[rt].mp.find( t ) == tree[rt].mp.end() ){
tree[rt].mp[t] = ++tot;
tree[tot].cls();
rt = tot;
}else rt = tree[rt].mp[t];
g[x].PB( rt ); cnt[rt]++;
if( s[s.length() - 1] == '?' ) break;
}
cin >> s;
PII t = gethash();
for( int i = 0 ; i < (int)g[x].size() ; ++i )
tree[g[x][i]].cnt[t]++;
}
double f[111][maxn] , mx[maxn];
#define mapi map<PII,int>::iterator
inline void cmax( double &x , double y ){ x = (x > y ? x : y); }
inline double _max( double x , double y ){ return x > y ? x : y ; }
int main(){
cin >> T >> N;
tree[tot = 0].cls();
rep( i , 1 , N ) build( i );
rep( i , 0 , tot ){
mx[i] = 0.0;
for( mapi u = tree[i].cnt.begin() ; u != tree[i].cnt.end() ; ++u )
cmax( mx[i] , ( 1.0 * (*u).se / cnt[i] ) );
}
rep( i , 1 , T ){
per( j , tot , 0 ){
double t = 0;
for( mapi u = tree[j].mp.begin() ; u != tree[j].mp.end() ; ++u )
t += f[i - 1][(*u).se] * cnt[(*u).se];
f[i][j] = _max( f[i - 1][0] + mx[j] , t / cnt[j] );
}
}
printf("%.12lf\n" , (double)f[T][0]);
return 0;
}