中山纪中集训Day15游记+8.15模拟赛题解

Part.I 游记

今天真浮躁啊,明天就要回重庆了QAQ。。。

然后我们就不想做题了,我勉强写一下前两个题的题解吧,第三个题就只做一个题面展示好了。。。

Part.II 题解

A.投票

题目

题目描述

输入

输出

样例输入

Sample 1:
2 2
0.50 0.50
Sample 2:
4 2
0.00 0.00 1.00 1.00
Sample 3:
3 2
0.75 1.00 0.50

样例输出

Sample 1:
0.5
Sample 2:
1.0
Sample 3:
0.5

数据范围

样例解释

分析

先说一个毒瘤结论:将概率按从小到大的顺序排序后,我们取的人数是在前缀和后缀上的一段。

我也不会证明(如有会证明的请在评论区留言谢谢)

然后我们就跑DP就是了。

参考代码

#include<cstdio>
#include<algorithm>
using namespace std;

const int Maxn=2000;

int N,K;
double P[Maxn+5];
double f_pre[Maxn+5][Maxn+5],f_suf[Maxn+5][Maxn+5];

int main() {
//	#ifdef LOACL
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
//	#endif
	freopen("vote.in","r",stdin);
	freopen("vote.out","w",stdout);
	scanf("%d %d",&N,&K);
	for(int i=1;i<=N;i++)
		scanf("%lf",&P[i]);
	sort(P+1,P+N+1);
	f_pre[0][0]=1;
	for(int i=1;i<=K;i++)
		for(int j=0;j<=i;j++) {
			f_pre[i][j]=f_pre[i-1][j]*(1-P[i]);
			if(j)f_pre[i][j]+=f_pre[i-1][j-1]*P[i];
		}
	reverse(P+1,P+N+1);
	f_suf[0][0]=1;
	for(int i=1;i<=K;i++)
		for(int j=0;j<=i;j++) {
			f_suf[i][j]=f_suf[i-1][j]*(1-P[i]);
			if(j)f_suf[i][j]+=f_suf[i-1][j-1]*P[i];
		}
	double ans=0;
	for(int i=0;i<=K;i++) {
		double tmp=0;
		for(int j=0;j<=K/2;j++)
			tmp+=f_pre[i][j]*f_suf[K-i][K/2-j];
		ans=max(ans,tmp);
	}
	printf("%.6f\n",ans);
	return 0;
}

B.动态数点

题目

题目描述

输入

输出

样例输入

Sample 1:
5
4 6 9 3 6
Sampla 2:
30
15 15 3 30 9 30 27 11 5 15 20 10 25 20 30 15 30 15 25 5 10 20 7 7 16 2 7 7 28 7

样例输出

Sample 1:
1 3
2
Sample 2:
1 13
9

数据范围

分析

我们可设计一个 O ( N log ⁡ 2 2 N ) O(N{\log_2}^2N) O(Nlog22N)的做法:

我们发现当一个区间所有数的GCD等于当前最小的数时,这个区间一定是“好”的。

那么我们可以用线段树维护区间GCD和最小值(也可以用ST表),然后枚举左端点,对每个左端点二分长度即可。

这里有一个 O ( N ) O(N) O(N)的做法:我们发现两个区间不相交时答案最好,所以我们就可以设计一个算法:对于一个位置 i i i,暴力找出以它为 a k a_k ak向右能找到的最远的地方 r i r_i ri,然后我们计算贡献,并将 i i i跳到 r i + 1 r_i+1 ri+1

这个算法的正确性我暂时没有证明,若有证明可在评论区留言。

参考代码

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

typedef unsigned int ui;
const int Maxn=500000;

int N;
ui A[Maxn+5];
bool vis[Maxn+5];

int main() {
//	#ifdef LOACL
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
//	#endif
	freopen("point.in","r",stdin);
	freopen("point.out","w",stdout);
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
		scanf("%d",&A[i]);s
	vector<int> ans_pos;
	int ans_max=0;
	for(int i=1,l,r;i<=N;i=r+1) {
		l=r=i;
		while(l>1&&A[l-1]%A[i]==0)
			l--;
		while(r<N&&A[r+1]%A[i]==0)
			r++;
		if(r-l==ans_max)
			ans_pos.push_back(l);
		if(r-l>ans_max)
			ans_max=r-l,ans_pos.clear(),ans_pos.push_back(l);
	}
	printf("%d %d\n",ans_pos.size(),ans_max);
	for(int i=0;i<(int)ans_pos.size();i++)
		printf("%d ",ans_pos[i]);
	puts("");
	return 0;
}

C.演员

题目

题目描述

输入

输出

样例输入

INPUT1
4 2
INPUT2
20 10
INPUT3
233 66
INPUT4
233333 23

样例输出

OUTPUT1
14
OUTPUT2
735074861
OUTPUT3
325609346
OUTPUT4
185055969

数据范围

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值