CSUST--3.28排位周赛第六场 (全解)

emmm,这次是DP场,不知道情况怎么样,蒟蒻的我在两个小时最多也就出个4题,压缩字符串那题对于蒟蒻的我来说确实有点难搞。。。

然后看你们6分钟出了tomjobs的那题,21分钟出了期望DP的那题。。。我以为你们能AK的。。结果2个多小时后还是2题。。。。。不知道种花那题为啥没什么人写

比赛链接:http://acm.csust.edu.cn/contest/83

比赛过后无法提交,请到problem中提交

题目说明:

pph的篮球考试(期望DP)

摸鱼的tomjobs(简单DP)

万能代码(区间DP)

序列变换(简单DP)

种花(数学期望)

pph的篮球考试

题目大意:每个球的投中率为$\frac{1}{a_i}$,问你分别投中$n,n-1,n-2,n-3,n-4,n-5$个球的概率(n<=1e6),输出答案在998244353下的逆元

Sample Input 

5
2 3 4 5 6

Sample Output

641926577 644699478 658563983 686292993 196875970 166374059

emmm,怎么说呢。。。一看10MB的限制内存就感觉是pph这个老阴比出的题目,又想来一手卡内存。大概看一下题目就知道是期望DP,那么根据上一次一步两步的经验我们应该知道这种10MB的东西的每一步的dp应该可以由上一步得出,也就是说我们的可以开dp[2][10]。。。。代表什么呢,我们先不忙着压缩内存,设有dp为dp[n][10],由于我们只需要最多5个球不中的概率,所以我们dp[i][j]可以代表第已经投了$i$次,有$j$次没有投中的概率。那么状态转移方程就很好写了:$dp[i][j]=dp[i-1][j]*\frac{1}{a_i}+dp[i-1][j-1]*(1-\frac{1}{a_i})$。。。其实这题和之前牛客寒训的期望DP有些类似,只不过那题更简单

然后。。。我们又可以通过不断异或1来交错dp[0/1][10]的步骤了

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mod=998244353;
typedef long long ll;
const int mac=1e6+10;

ll dp[2][10];

ll qick(ll a,ll b)
{
    ll ans=1;
    while (b){
        if (b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

int main()
{
    int n;
    scanf ("%d",&n);
    int flag=1;
    dp[0][0]=1;
    for (int i=1; i<=n; i++){
        ll x;
        scanf ("%lld",&x);
        x=qick(x,mod-2);
        for (int j=0; j<=5; j++){//j个球没有投中的概率
            if (j>0)
                dp[flag][j]=dp[flag^1][j]*x%mod+dp[flag^1][j-1]*(1-x+mod)%mod;
            else dp[flag][j]=dp[flag^1][j]*x%mod;
            dp[flag][j]%=mod;
        }
        flag^=1;
    }
    for (int i=0; i<6; i++){
        printf ("%lld%c",dp[flag^1][i],i==6?‘\n‘:‘ ‘);
    }
    return 0;
}

摸鱼的tomjobs

题目大意:给你n个数,你要选择其中某些数使得这些数的和最大,当你选择$a_i$时,值为$a_i-1,a_i+1$的数就不能选择了

Sample Input 

10
1 1 2 2 3 3 4 4 5 5

Sample Output 

18

这题我们可以用DP来写,这个DP的话非常简单,设该数取或者不取为$dp[1/0][i]$那么如果取了该数,则答案是由没有取$i-1$转移过来的。也就是说$dp[1][i]=dp[0][i-1]+a[i]$其中$a[i]$表示值为$i$的总和,如果不取这个数的话。。。没什么好说的就是上一次的最大值了

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e5+10;
typedef long long ll;

ll dp[2][mac];//0:不拿,1拿
ll a[mac];

int main()
{
    int n;
    scanf ("%d",&n);
    int mx=0;
    for (int i=1; i<=n; i++){
        int x;
        scanf ("%d",&x);
        a[x]+=x;
        mx=max(mx,x);
    }
    for (int i=1; i<=mx; i++){
        dp[0][i]=max(dp[0][i-1],dp[1][i-1]);
        dp[1][i]=dp[0][i-1]+a[i];
    }
    printf ("%lld\n",max(dp[0][mx],dp[1][mx]));
    return 0;
}

万能代码

题目大意:给你一个字符串,问你可以将其压缩的最短长度,压缩规则:M标记重复串的开始,R重复上一个M(如果左边没有M,则从开始算起)到第一个大写字母的解压结果,例如:bcdcdcd可以压缩为bMcdRR,abcabcdabcabcdxyxyz 可以压缩为abcabcdRMxyRz(字符串长度<=50)

Sample Input 

bcdcdcdcdxcdcdcdcd

Sample Output 

14

emmm,区间DP,枚举区间长度,枚举起点得终点,枚举当前区间压缩长度,判断是否合理。$dp[i][j]$为第$i$位到第$j$的最短长度,计算在当前合理的情况下的最小长度应该是:$dp[star][ends]=min((star!=1)+len/xlen-1+xlen)$即有len/xlen个重复串,其中len表示区间长度,则有len/xlen-1个R和1个原串有没有M就看起点是否为1了,接下来就是状态转移维护整个区间的最小长度,该区间中每一小段的最小长度是已知的,转移也就是区间合并,即$dp[i][j]=min(dp[i][k]+dp[k+1][j])$

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

char s[55];
int dp[55][55];

int ok(int st,int ed,int len)
{
    int sm=ed-st+1;
    if (sm%len) return 0;
    for (int i=len; i<sm; i++){
        int p=i%len;
        if (s[st+p]!=s[st+i]) return false;
    }
    return 1;
}

int main()
{
    scanf ("%s",s+1);
    int slen=strlen(s+1);
    for (int i=1; i<=slen; i++)
        dp[i][i]=1;
    for (int len=2; len<=slen; len++){
        for (int star=1; star+len-1<=slen; star++){
            int ends=star+len-1;
            dp[star][ends]=len;
            for (int xlen=2; xlen<=len/2; xlen++){
                if (ok(star,ends,xlen)){
                    dp[star][ends]=min(dp[star][ends],(star!=1)+len/xlen-1+xlen);
                    //有len/xlen个重复串,则有其-1个R和1个原串
                }
            }
            for (int tail=star; tail<ends; tail++)
                dp[star][ends]=min(dp[star][ends],dp[star][tail]+dp[tail+1][ends]);
        }
    }
    printf ("%d\n",dp[1][slen]);
    return 0;
}

序列变换

题目大意:有一个01序列,$S_0=0,S_1=01,S_2=0110...$即$S_k$是$S_{k-1}$的基础上将0替换成01,1替换成10后的结果,让你求$S_n$有多少个00,01,10,11串,对998244353取模

Sample Input 

1

Sample Output 

0 1 0 0

emmmm,简单来讲,县找一波规律就会发现$S_k$是$S_{k-1}$的基础上加上将$S_{k-1}$的0替换成1,将1替换成0的结果。

那么这就很好办了,一眼DP设dp[n][4]分别保存00,01,10,11的数量,我们可以知道,这一次的00是由上一次的11转移过来的,即$dp[i][0]=dp[i-1][0]+dp[i-1][3]$,其他的也是这样互相转换的,但需要注意的是合并的时候由于头一直是0,所以不用考虑,但尾巴一直在变动,所以在$S_k$和$S_k‘$合并的时候注意一下中间的是什么就好了。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e5+10;
typedef long long ll;
const int mod=998244353;

ll dp[mac][4];//00,01,10,11

int main()
{
    int n;
    scanf ("%d",&n);
    dp[1][1]=1;
    dp[2][1]=1;dp[2][2]=1;dp[2][3]=1;
    int head=0,tail=0;
    for (int i=3; i<=n; i++){
        dp[i][0]=dp[i-1][0]+dp[i-1][3];
        dp[i][1]=dp[i-1][1]+dp[i-1][2];
        dp[i][2]=dp[i-1][2]+dp[i-1][1];
        dp[i][3]=dp[i-1][3]+dp[i-1][0];
        if (tail==0)dp[i][1]++;
        else dp[i][3]++;
        dp[i][0]%=mod;dp[i][1]%=mod;
        dp[i][2]%=mod;dp[i][3]%=mod;
        tail^=1;
    }
    printf ("%lld %lld %lld %lld\n",dp[n][0],dp[n][1],dp[n][2],dp[n][3]);
    return 0;
}

种花

题目大意:给你n个员工,首尾相接,每个员工的种花量在$l_i,r_i$之间,如果相邻的两个员工的种花量的乘积为质数$p$的倍数,那么老板将奖励每个员工各1000元,问老板发的所有奖励期望对1e9+7取模

Sample Input 

3 2
1 2
420 421
420420 420421

Sample Output

4500

emmmm,差不多是个签到题的压子。我们求出每个区间取得的$p$倍的概率$a_i$,那么两两员工之间得到$p$倍数的概率就是$1-(1-a_i)*(1-a_{i+1})$,我们把这些概率全部加起来,最后乘以2000就完事了

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e5+10;
const int mod=1e9+7;
typedef long long ll;

ll nb[mac];

ll qick(ll a,ll b)
{
    ll ans=1;
    while (b){
        if (b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

int main()
{
    int n,p;
    scanf ("%d%d",&n,&p);
    for (int i=1; i<=n; i++){
        ll l,r;
        scanf ("%lld%lld",&l,&r);
        nb[i]=r/p-(l-1)/p;//计算l-r中有几个p的倍数
        nb[i]=nb[i]*qick(r-l+1,mod-2)%mod;//计算取得这些数的概率
    }
    nb[n+1]=nb[1];
    ll ans=0;
    for (int i=1; i<=n; i++){
        ans=ans+(1-(((1-nb[i]+mod)%mod)*((1-nb[i+1]+mod)%mod)%mod)+mod)%mod;
        ans%=mod;
        //1扣去都不行的概率
    }
    printf ("%lld\n",ans*2000%mod);
    return 0;
}

原文地址:https://www.cnblogs.com/lonely-wind-/p/12555711.html

时间: 2024-10-11 20:41:44

CSUST--3.28排位周赛第六场 (全解)的相关文章

2014多校第六场 1005 || HDU 4925 Apple Tree

题目链接 题意 : 给你一块n×m的矩阵,每一个格子可以施肥或者是种苹果,种一颗苹果可以得到一个苹果,但是如果你在一个格子上施了肥,那么所有与该格子相邻(指上下左右)的有苹果树的地方最后得到的苹果是两倍,如果(i,j)有一颗苹果树,(i-1,j)与(i,j+1)施了肥,那么苹果应该是1的两倍2,2的两倍4,最后是4个苹果,问你怎么安排苹果和施肥的格子使最后得到的苹果最多. 思路 : 画了图就可以看出来,苹果和苹果,肥与肥之间不要相邻就好了,所有的苹果之间都有施肥,所有施肥的格子都被苹果隔开了才能

【HDU】4923 Room and Moor(2014多校第六场1003)

Room and Moor Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 263    Accepted Submission(s): 73 Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0

2014多校第六场 || HDU 4927 Series 1(杨辉三角组合数)

题目链接 题意 : n个数,每操作一次就变成n-1个数,最后变成一个数,输出这个数,操作是指后一个数减前一个数得到的数写下来. 思路 : 找出几个数,算得时候先不要算出来,用式子代替,例如: 1 2 3 4 5 6 (2-1) (3-2) (4-3) (5-4)(6-5) (3-2-2+1)(4-3-3+2)(5-4-4+3)(6-5-5+4) (4-3-3+2-3+2+2-1)(5-4-4+3-4+3+3-2)(6-5-5+4-5+4+4-3) (5-4-4+3-4+3+3-2-4+3+3-2

2014多校第六场 1010 || HDU 4930 Fighting the Landlords (模拟)

题目链接 题意 : 玩斗地主,出一把,只要你这一把对方要不了或者你出这一把之后手里没牌了就算你赢. 思路 : 一开始看了第一段以为要出很多次,实际上只问了第一次你能不能赢或者能不能把牌出尽. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std ; 6 7 char str1[20],str2[20] ; 8 int hash1[20],hash2[2

HDOJ多校联合第六场

先一道一道题慢慢补上, 1009.题意,一棵N(N<=50000)个节点的树,每个节点上有一个字母值,给定一个串S0(|S0| <=30),q个询问,(q<=50000),每次询问经过两个点u,v之间的路径上的字母构成字符串S,问S0在S中作为序列出现了多少次. 分析:对于每次询问需要知道其LCA,设w = LCA(u, v),可以用tarjan处理出来,或者倍增法也行.然后w会将S0分成两部分,记做S1,S2,然后分别考虑S1在u->w的路径出现次数,以及S2在v->w出现

2014多校联合-第六场

最近这两场好无奈啊... 今天这场最后30分钟敲1001,压力倍增,虽然思路比较明确,但是代码打起来不怎么容易. 但是还是好在25分钟左右debug结束.提交wa,再提交,依然WA.......最后5分钟,还是没有AC掉. 一开始以为是精度问题,后来才sb的发现原来数组开小了. 在压力环境下保证代码的效率和质量真不是一件容易的事情.不过数组开小了,真是不可原谅. 1001:Map 题目相当于几条链表.把链表排成几行. 然后枚举每一列的状态会被操作多少次. 然后把和累加起来,然后直接除以状态总数.

多校第六场 HDU 4927 JAVA大数类

题目大意:给定一个长度为n的序列a,每次生成一个新的序列,长度为n-1,新序列b中bi=ai+1?ai,直到序列长度为1.输出最后的数. 思路:这题实在是太晕了,比赛的时候搞了四个小时,从T到WA,唉--对算组合还是不太了解啊,现在对组合算比较什么了-- import java.io.*; import java.math.*; import java.util.*; public class Main { public static void main(String[] args) { Sca

组队赛第六场:贪心+RMQ加二分

UVALive 6606 Meeting Room Arrangement COJ有这题,一模一样的,COJ应该是从这个OJ上拿的吧. 按右端点排序,然后从第一个开始贪心的取相邻的. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<set> #in

HDU 4923 Room and Moor (多校第六场C题) 单调栈

Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0 or 1. In order to beat him, programmer Moor has to construct another sequence B = {B1, B2,... , BN} of the same length, which satisfies that: Input The inp