• 【模拟赛】纪中提高A组 19.8.15 测试


    Task.1 投票

    题目大意:有 (n) 个同学投票,每个人有一个投赞成票的概率 (p_i)。现在要从中选出 (k) 个同学,使得这 (k) 个人投票的平票的概率最大。

    数据范围:(1leq N,Kleq 2000)

    考场上自己生成数据找规律发现一定是对所有人的 (p_i) 排序后头尾各取几个人(可以不取),(O(N^2)) DP 拿到了 (70)。这个性质的正确性具体来说就是假设已经确定了一些人,再选一个人结果是关于选的这个人的 (p) 的一个一次函数(其他部分已经确定,为常数)。具体推导可以看:here。利用这条性质,我们只需要对前缀后缀各 (O(N^2)) 做一遍DP算出概率再 (O(N)) 枚举前面选几个人即可。复杂度 (O(N^2))

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    typedef double db;
    const int N=2005;
    int n,k;
    db p[N],c[N],f[N][N],g[N][N],ans=0;
    
    int main(){
    	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);
    	for(int i=n-k+1;i<=n;i++)c[n+1-i]=p[i];
    	f[0][0]=g[0][0]=1.0;
    	for(int i=1;i<=k;i++){
    		for(int j=0;j<=i;j++){
    			f[i][j]=f[i-1][j]*(1.0-p[i]);
    			if(j>0)f[i][j]+=f[i-1][j-1]*p[i];
    			g[i][j]=g[i-1][j]*(1.0-c[i]);
    			if(j>0)g[i][j]+=g[i-1][j-1]*c[i];
    		}
    	}
    	for(int i=0;i<=k;i++){
    		db tmp=0;
    		for(int j=0;j<=k/2;j++)tmp+=f[i][j]*g[k-i][k/2-j];
    		ans=max(ans,tmp);
    	}
    	printf("%lf
    ",ans);
    	return 0;
    }
    

    Task.2 动态数点

    题目大意:对于一个数列 (a),如果一段区间 ([l,r]) 中存在 (a_k) 满足 (forall i a_k|a_i),这段区间的价值就是 (r-l)。给出序列 (a),求出所以区间中最大的价值以及哪些区间价值最大。

    数据范围:(1leq Nleq 5cdot 10^5,1leq a_ileq 2^{32}-1)

    存在不止一个 (O(Nlog N)) 的解法,比如预处理一个区间 (gcd) 的ST表,然后对于每一个位置考虑能不能作为 (a_k),向左向右拓展,比较区间 (gcd) 是否是它的倍数。

    这里给出一种 (O(N)) 的解法:先从小到大枚举作为 (a_k) 向右边能拓展到的最远距离,这个时候这段距离中经过的点一定不会比当前的点更优,然后在倒着向左边做同样的事情,在这个过程中记录和更新答案即可,因为操作顺序的缘故,得到的答案也是有序的。

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    template<class T>void read(T &x){
    	x=0; char c=getchar();
    	while(c<'0'||'9'<c)c=getchar();
    	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
    }
    typedef long long ll;
    const int N=500050;
    int n;
    ll a[N];
    int left[N],right[N],len=-1,p[N],tot;
    int main(){
    	freopen("point.in","r",stdin);
    	freopen("point.out","w",stdout);
    	read(n);
    	for(int i=1;i<=n;i++) read(a[i]);int l,r; ll t;
    	for(int k=1;k<=n;){
    		r=k; t=a[k];
    		while(r<n&&a[r+1]%t==0)++r;
    		right[k]=r; k=r+1;
    	}
    	for(int k=n;k;k--)if(right[k]){
    		l=k; t=a[k];
    		while(l>1&&a[l-1]%t==0)--l;
    		left[k]=l;
    	}
    	for(int i=1;i<=n;i++){
    		if(right[i]-left[i]>len){
    			len=right[i]-left[i];
    			p[tot=1]=left[i];
    		}
    		else if(right[i]-left[i]==len)
    			p[++tot]=left[i];
    	}
    	printf("%d %d
    ",tot,len);
    	for(int i=1;i<=tot;i++)printf("%d ",p[i]); puts("");
    	return 0;
    }
    

    Task.3

    题目大意:

    数据范围:

    正解 DP,非常有趣但是我没完全理解,坑待填。

  • 相关阅读:
    Java入门
    Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8
    pypy3.8安装
    asyncio执行阻塞代码
    linux安装go
    python消费rabbitmq
    绑定进程到指定cpu运行
    负载均衡算法
    django版本规划
    FastAPI WebSocket 简单演示
  • 原文地址:https://www.cnblogs.com/opethrax/p/11396575.html
Copyright © 2020-2023  润新知