P3041 [USACO12JAN]Video Game Combos【AC自动机+DP】

时空限制 1000ms / 128MB

题目描述

Bessie is playing a video game! In the game, the three letters ‘A’, ‘B’, and ‘C’ are the only valid buttons. Bessie may press the buttons in any order she likes; however, there are only N distinct combos possible (1 <= N <= 20). Combo i is represented as a string S_i which has a length between 1 and 15 and contains only the letters ‘A’, ‘B’, and ‘C’.

Whenever Bessie presses a combination of letters that matches with a combo, she gets one point for the combo. Combos may overlap with each other or even finish at the same time! For example if N = 3 and the three possible combos are “ABA”, “CB”, and “ABACB”, and Bessie presses “ABACB”, she will end with 3 points. Bessie may score points for a single combo more than once.

Bessie of course wants to earn points as quickly as possible. If she presses exactly K buttons (1 <= K <= 1,000), what is the maximum number of points she can earn?

贝西在玩一款游戏,该游戏只有三个技能键 “A”“B”“C”可用,但这些键可用形成N种(1 <= N<= 20)特定的组合技。第i个组合技用一个长度为1到15的字符串S_i表示。

当贝西输入的一个字符序列和一个组合技匹配的时候,他将获得1分。特殊的,他输入的一个字符序列有可能同时和若干个组合技匹配,比如N=3时,3种组合技分别为"ABA", “CB”, 和"ABACB",若贝西输入"ABACB",他将获得3分。

若贝西输入恰好K (1 <= K <= 1,000)个字符,他最多能获得多少分?

输入格式:
  • Line 1: Two space-separated integers: N and K.

  • Lines 2…N+1: Line i+1 contains only the string S_i, representing combo i.

输出格式:
  • Line 1: A single integer, the maximum number of points Bessie can obtain.

题目分析

AC自动机的DP永远都一个套路
d p [ i ] [ j ] dp[i][j] dp[i][j]表示已完成字符串前 i i i位,当前在AC自动机上结点 j j j,最多可得多少分
初始化为 d p [ 0 ] [ 0 ] = 0 dp[0][0]=0 dp[0][0]=0,其余为-INF
d p [ i ] [ c h [ j ] [ k ] ] = m a x ( d p [ i ] [ c h [ j ] [ k ] ] , d p [ i − 1 ] [ j ] + n u m [ c h [ j ] [ k ] ] ) dp[i][ch[j][k]]=max(dp[i][ch[j][k]],dp[i-1][j]+num[ch[j][k]]) dp[i][ch[j][k]]=max(dp[i][ch[j][k]],dp[i1][j]+num[ch[j][k]])
注意一个技能是另一个技能子串时,技能个数要累加到那个最长的字符串上


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
typedef double dd;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=1010;
int n,L;
int rem[maxn],cnt;
int ch[maxn][5],fail[maxn];
int dp[maxn][maxn],ans;
char pt[maxn];

void ins(char* ss,int len)
{
    int u=0;
    for(int i=0;i<len;++i)
    {
        int x=ss[i]-'A';
        if(!ch[u][x]) ch[u][x]=++cnt;
        u=ch[u][x];
    }
    rem[u]++;
}

void ACM()
{
    queue<int> q;
    for(int i=0;i<3;++i)
    if(ch[0][i]) fail[ch[0][i]]=0,q.push(ch[0][i]);
    
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=0;i<3;++i)
        {
            if(!ch[u][i]) ch[u][i]=ch[fail[u]][i];
            else{
                fail[ch[u][i]]=ch[fail[u]][i];
                q.push(ch[u][i]);
                rem[ch[u][i]]+=rem[fail[ch[u][i]]];
            }
        }
    }
}

void DP()
{
    memset(dp,128,sizeof(dp)); 
    dp[0][0]=0;
    
    for(int i=1;i<=L;++i)
    for(int j=0;j<=cnt;++j)
    {
        for(int k=0;k<3;++k)
        dp[i][ch[j][k]]=max(dp[i][ch[j][k]],dp[i-1][j]+rem[ch[j][k]]);
    }
    
    for(int i=0;i<=cnt;++i)
    ans=max(ans,dp[L][i]);
}

int main()
{
    n=read();L=read();
    for(int i=1;i<=n;++i)
    {
        scanf("%s",&pt);
        ins(pt,strlen(pt));
    }
    
    ACM(); DP();
    printf("%d",ans);
    return 0;
}
以下是P4087 [USACO17DEC]Milk Measurement的c++代码: ```c++ #include<bits/stdc++.h> using namespace std; int n,d,i,x,minn=1e9,maxn=-1e9,sum=7;//注意sum要初始化为7,因为一开始有三个人挤奶! map<int,int> mp; struct node{ int day,milk,id;//day表示某一天,milk表示这一天的产奶量,id表示这头牛的编号 }a[100010]; bool cmp(node x,node y){ return x.day<y.day; } int main(){ scanf("%d%d",&n,&d); for(i=1;i<=n;i++){ scanf("%d%d%d",&a[i].day,&a[i].id,&a[i].milk); minn=min(minn,a[i].id);//记录最小的牛的编号 maxn=max(maxn,a[i].id);//记录最大的牛的编号 } sort(a+1,a+n+1,cmp);//排序 for(i=1;i<=n;i++){ int p=a[i].id; mp[p]+=a[i].milk;//记录每头牛产奶总量 if(mp[p]-a[i].milk>=mp[minn]&&mp[p]>=mp[minn]){//如果这头牛的产奶总量减去这一天的产奶量后等于最小产奶量且这头牛的产奶总量大于等于最小产奶量 sum--; } if(mp[p]>=mp[maxn]&&mp[p]-a[i].milk<mp[maxn]){//如果这头牛的产奶总量大于等于最大产奶量且这头牛的产奶总量减去这一天的产奶量小于最大产奶量 sum++; } if(mp[p]-a[i].milk<mp[maxn]&&mp[p]>=mp[maxn]){//如果这头牛的产奶总量减去这一天的产奶量小于最大产奶量且这头牛的产奶总量大于等于最大产奶量 if(mp[maxn]-mp[p]+a[i].milk>0)sum++; } mp[p]-=a[i].milk;//减去这一天的产奶量 if(i==n||a[i].day!=a[i+1].day){//如果到了新的一天或者到了最后一天 if(mp[maxn]!=mp[a[i].id]&&mp[a[i].id]>=mp[maxn])sum++;//如果这头牛的产奶总量不等于最大产奶量且这头牛的产奶总量大于等于最大产奶量 if(mp[maxn]==mp[a[i].id]){//如果这头牛的产奶总量等于最大产奶量 if(a[i].id==maxn)sum+=0;//如果这头牛就是最大产奶量的牛,那么不需要增加计数器 else sum++;//否则需要增加计数器 } if(mp[minn]!=mp[a[i].id]&&mp[a[i].id]>=mp[minn])sum++;//如果这头牛的产奶总量不等于最小产奶量且这头牛的产奶总量大于等于最小产奶量 if(mp[minn]==mp[a[i].id]){ if(a[i].id==minn)sum+=0;//如果这头牛就是最小产奶量的牛,那么不需要增加计数器 else sum++;//否则需要增加计数器 } } } printf("%d\n",sum); return 0; } ``` 该题的解题思路是模拟,需要注意细节问题。我们可以首先将输入的数据按天数排序,然后模拟每一天挤奶的情况,并根据题目要求进行计数即可。具体细节请见代码注释。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值