【日常摸鱼】牛客挑战赛3
作者:互联网
【日常摸鱼】牛客挑战赛3
前言
无
A 珂学送分
期望dp,要用前缀和优化一下。。略了
B 遇见
比较水的追及问题。。。但是两个点一开始就在一起要特判掉。
C 位数差
稍微转化一下。。只用求数列中任意两对数的和的位数,这个可以随便套数据结构。
D 蝴蝶
思路大致跟上一场蝴蝶差不多。。而且比上场那个简单多了,连数据结构都不用套。。
E 迷宫
还没写。。
F 01序列
链接
https://ac.nowcoder.com/acm/contest/20/F
题意
给定长度为 n 的01序列,序列中部分位置已经确定,剩余部分01等概率出现。对最终序列求最长不下降序列(如有多种可能序列,则在此基础上最大化1的个数),设最长不下降序列的长度为 len,最长不下降序列中1的个数为 num,求期望 E(len * num) * 2 ^ 10000 对 1000000007 取模的结果。
\(n\leq 1000\)
题解
后面乘的2^10000没什么用,只是把前面E的分母都抵消了而已。。
于是我们要算的就是所有情况的len*num的总和。。
我们先考虑对已知序列,怎么求1最多的最长不下降子序列。。
最终的子序列必然是一段0和一段1。。。
我们从左往右依次考虑,假设当前序列的最优解是前面一段0,然后从第i个位置开始全选1。。
如果后面再放个1,直接取过来就行。。
如果后面放个0,如果从i开始的1的个数不少于0的个数,那么什么都不用做。
如果放0后,从i开始的0的个数大于1的个数,那么这一段全选0的长度一定优于全选1。于是这部分的1全部舍弃掉。
这个过程我们很容易能用dp来维护。。于是这题就做完了。
\(Code\)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=1e9;
const int N=1e3+100;
const LL P=1000000007;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
void pls(LL &x,LL y){
x+=y;if(x>=P)x-=P;
}
int n;
int a[N];
LL len[N][N],num[N][N],cnt[N][N],dp[N][N];
int main(){
int tt=10000;
n=read();
for(int i=1;i<=n;++i) a[i]=read();
cnt[0][0]=1;
for(int i=0;i<n;++i){
if(a[i+1]==-1) --tt;
for(int j=0;j<=i;++j){
if(a[i+1]!=1){
if(j>0) {
pls(len[i+1][j-1],len[i][j]);
pls(cnt[i+1][j-1],cnt[i][j]);
pls(num[i+1][j-1],num[i][j]);
pls(dp[i+1][j-1],dp[i][j]);
}
else{
pls(len[i+1][j],(cnt[i][j]+len[i][j])%P);
pls(cnt[i+1][j],cnt[i][j]);
}
}
if(a[i+1]!=0){
pls(len[i+1][j+1],(cnt[i][j]+len[i][j])%P);
pls(cnt[i+1][j+1],cnt[i][j]);
pls(num[i+1][j+1],(num[i][j]+cnt[i][j])%P);
pls(dp[i+1][j+1],(dp[i][j]+num[i][j]+len[i][j]+cnt[i][j])%P);
}
}
}
LL ans=0;
for(int i=0;i<=n;++i) pls(ans,dp[n][i]);
ans=(ans%P+P)%P;
for(int i=1;i<=tt;++i) pls(ans,ans);
printf("%lld\n",ans);
return 0;
}
标签:cnt,pls,int,len,牛客,num,摸鱼,序列,挑战赛 来源: https://www.cnblogs.com/Yuigahama/p/14397740.html