牛客OI周赛15-普及组

链接:https://ac.nowcoder.com/acm/contest/4911/A
来源:牛客网

题目描述

牛牛最近喜欢玩咪咪游戏,于是自己写了个程序编了个游戏让牛妹来玩。游戏是这样的:

牛牛有一个长的字符串(只包26含个小写字母),他想让牛妹判断这个字符串是好的。

定义一个串是好的: 这个串是由连续的mq连接而成的

比如 mqmq{mqmq}mqmq说明这个串是好的,mqmqm{mqmqm}mqmqm或mqmqx{mqmqx}mqmqx都是不好的。现在牛牛 想问牛妹这个串是否是好的,如果好的输出Yes{Yes}Yes,否则输出No{No}No
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
#include<map>
using namespace std;
const long long p=1e9+7;
#define maxn 700000
long long ans,n,k;
char a[maxn];
int main()
{
    cin>>n;
    while(n--)
    {
        int ok=0;
        memset(a,0,sizeof(a));
        cin>>a;
        for(int i=0;i<strlen(a);i+=2)
        {
            if(a[i]!='m'||a[i+1]!='q'){
               ok=1; cout<<"No"<<endl;break;
            }
        }
        if(!ok) cout<<"Yes"<<endl;
    }
}

链接:https://ac.nowcoder.com/acm/contest/4911/B
来源:牛客网

题目描述

上天眷顾了牛牛,给牛牛n个宝盒。牛牛会从这n个箱子中各取一件宝物去当掉来换钱(每个箱子中有 mi件宝物)。
牛牛想知道他用不同的方法取宝物能当来的钱数量的前k小值,为了避免输出量过大只要输出 ∑ai(i≤k)\sum a_i (i \leq k)ai(ik)即可,其中的 ai为第i小值。
有种分组背包的感觉;当时看到第i小就想到了线段树,当然不知道怎么写!!题解很棒,dp【i】【j】从第i个箱子中取出第j个物品,此时的方法数!!(我感觉我好想写过
这篇题解),算出最大能取出的值sum,接下来有点类似背包;i从1到n枚举,到第i个背包时的方法,dp【i】【j】+=dp【i-1】【j-w[i]】;
 
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
#include<map>
using namespace std;
const long long p=998244355;
#define maxn 20000
#define lson ((pos)*2)
#define rson ((pos)*2+1)
int m,ans,sum,dp[200][maxn],a[200][maxn],n;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int tot=0;
        cin>>a[i][0];
        for(int j=1;j<=a[i][0];j++)
            cin>>a[i][j],tot=max(a[i][j],tot);
        sum+=tot;
    }
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int h=1;h<=a[i][0];h++)//第i个背包的物品数
        for(int j=sum;j>=a[i][h];j--)//有多少种方法
            dp[i][j]+=dp[i-1][j-a[i][h]];
    }//最后选择dp[n][]
    int coun=0;
    for(int i=1;i<=sum;i++)
    {
        while(dp[n][i]){
            ans+=i;
            dp[n][i]--;
            coun++;
            if(coun==m) {
                    cout<<ans;return 0;
            }
        }
    }

    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/4911/C
来源:牛客网

题目描述

牛牛给牛妹出了到简单区间加题,牛妹觉得太简单于是稍微修改了一下。

牛妹有个长为 n{n}n的序列A{A}A。每次牛妹会选择这个序列中的一段区间进行区间加1{1}1,但是要满足的条件:对于任意两次区间加的起始,结束位置各不相同。

现在牛妹问你存在多少种区间加方式使得最后得到的序列使得∀Ai=m{∀ A_i=m}Ai=m,由于方案数过多,答案对998244355取模。
 
这道题很nb!并没想到用()来表示,尽管有人数,样例的解释就是用括号,可以推出。
所求答案为方案数,不是区间修改,不是求和之类的,又没明确单调性,就考虑dp吧。按题解,用括号表示,首先需要合法,即左括号小于等于右括号的数目;
dp【i】【j】(i表示到达第i个数时,“(”比 “)”多j个);
then就需要分情况找状态转移方程,对于某个位置i,可以放置左括号或右括号,(和),以及不放
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
#include<map>
using namespace std;
const long long p=998244355;
#define maxn 5000
#define lson ((pos)*2)
#define rson ((pos)*2+1)
long long ans,n,m,k,l;
long long  a[maxn],dp[maxn][maxn];
int main()
{
   cin>>n>>m;
    bool ok=0;
   for(int i=1;i<=n;i++){ cin>>a[i];if(a[i]>m) ok=1;}
    if(ok) cout<<0<<endl;
    else {
        if(a[1]==m) dp[1][0]=1;
        if(a[1]==m-1) dp[1][1]=1,dp[1][0]=1;
        for(int i=2;i<=n;i++)
        {
            dp[i][m-a[i]]=(dp[i][m-a[i]]+dp[i-1][m-a[i]-1])%p;
            dp[i][m-a[i]-1]=(dp[i][m-a[i]-1]+dp[i-1][m-a[i]-1]*(m-a[i]))%p;
            dp[i][m-a[i]]=(dp[i][m-a[i]]+dp[i-1][m-a[i]])%p;
            dp[i][m-a[i]-1]=( dp[i][m-a[i]-1]+dp[i-1][m-a[i]]*(m-a[i]))%p;
        }
        cout<<dp[n][0];
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Showend/p/12716770.html