zoukankan      html  css  js  c++  java
  • 8.7 正睿暑期集训营 Day4


    2018.8.7 正睿暑期集训营 Day4

    时间:5h(实际)
    期望得分:...
    实际得分:...
    _(:зゝ∠)_

    比赛链接

    A 世界杯(贪心)

    题目链接

    设法国队赔率为x,克罗地亚赔率为y,则一个人会在x>=1/p时下注法国队((x*pi*aigeq ai))。
    那么按1/p从小到大排序,下注法国的一定是一个前缀。同理,下注克罗地亚队的一定是一个后缀(1/(1-p))。
    一个人下注相当于得到ai收益,但是可能会付 (赔率*ai) 的代价。当x增大时,法国赢了时代价就会变大,要让y适当增大来获得收益。
    即y随x增大而增大。可以枚举x。
    设投法国收益为w1,代价cost1=w1x;克罗地亚收益w2,代价cost2=w2x。
    某种情况的收益是min(w1-cost2, w2-cost1),x增大w1,cost1增大,要最大化min就要增大w2,即y一定单调增大。

    三分套三分套二分为什么WA呢。。

    //365ms	16532kb(rank2 800+ms 学了一波double read() 233)
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 400000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    const int N=1e6+5;
    
    int n;
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Node
    {
    	double a,p;
    	bool operator <(const Node &node)const{
    		return p>node.p;
    	}
    }A[N];
    
    inline double read()
    {
    	double x=0,y=0.1; register char c=gc();
    	for(; !isdigit(c)&&c!='.'; c=gc());
    	for(; isdigit(c); x=x*10+c-'0',c=gc());
    	for(c=='.'&&(c=gc()); isdigit(c); x+=(c-'0')*y,y*=0.1,c=gc());
    	return x;
    }
    
    int main()
    {
    //	freopen("a.in","r",stdin);
    //	freopen("a.out","w",stdout);
    
    	n=read();
    	for(int i=1; i<=n; ++i) A[i].a=read(), A[i].p=read();//scanf("%lf%lf",&A[i].a,&A[i].p);
    	std::sort(A+1,A+1+n);
    
    	double Ans=0,s1=0,s2=A[n].a/*初始肯定有的啊(or 0)*/,x,y1,y2;
    	for(int i=1,j=n; i<=n; ++i)
    	{
    		s1+=A[i].a, x=1.0/A[i].p;
    		y1=1.0/(1-A[j].p);
    		while(j>1)
    		{
    			y2=1.0/(1-A[j-1].p);
    			if(std::min(s1-(y1-1)*s2,s2-(x-1)*s1)<std::min(s1-(y2-1)*(s2+A[j-1].a),s2+A[j-1].a-(x-1)*s1))
    				y1=y2, s2+=A[--j].a;
    			else break;
    		}
    		Ans=std::max(Ans,std::min(s1-(y1-1)*s2,s2-(x-1)*s1));
    	}
    	printf("%.6lf
    ",Ans);
    
    	return 0;
    }
    

    B 数组(线段树)

    题目链接

    暴力的话,枚举每个左端点,然后找到(min{nxt_j}-1),加上这段区间长度。(枚举右端点,求(max{las_j}+1)也一样)
    如果不考虑区间内其它数的限制(只考虑本身重复的限制),如果我们能维护每个位置上次出现的位置(las)(set就可以),以(i)为右端点的区间长度就为(i-las+1)
    如果是算非法区间个数的话,(las)就是(i)的答案,so直接算非法的好了(这样枚举右端点更方便些)。
    现在考虑区间([las_i,i-1])内其它数对(i)延伸距离的限制,记其中最靠右的它第二次(从右往左)出现的位置为(right)(就是(max{las_j}))。
    (right<las_i),则答案就是(las_i);否则会将(i)拦住,(i)的答案就为(right)
    对于一个区间(i),答案的更新同理,只是在(right[before i]<right[i])时,答案的更新可能分成几部分,一部分会被(right[before i])限制,一部分其区间本身限制。递归即可。
    用线段树维护。
    (sum[rt](l,r))为只考虑([l,r])中数的限制,右端点(iin [l,r])时它们的贡献和,(sum[1])就是全局非法区间数。
    复杂度(O(nlog^2n))

    #include <set>
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=1e5+5;
    
    int n,A[N],las[N],las_v[N];
    std::set<int> st[N];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    struct Segment_Tree
    {
    	#define ls rt<<1
    	#define rs rt<<1|1
    	#define lson l,m,rt<<1
    	#define rson m+1,r,rt<<1|1
    	#define S N<<2
    	int right[S];
    	LL ans[S];
    
    	LL Calc(int l,int r,int rt,int Right)
    	{
    		if(l==r) return std::max(right[rt],Right);
    		int m=l+r>>1;
    		if(right[ls]<Right) return 1ll*(m-l+1)*Right+Calc(rson,Right);
    		return ans[rt]-ans[ls]+Calc(lson,Right);//部分左区间和整个右区间受限制,右区间此时的答案是ans[rt]-ans[ls]而不是ans[rs](rt已经限制住rs了)。
    	}
    	inline void Update(int l,int r,int m,int rt)
    	{//考虑左区间对右区间的限制 
    		if(right[ls]>=right[rs]) right[rt]=right[ls], ans[rt]=ans[ls]+1ll*(r-m)*right[ls];
    		else right[rt]=right[rs], ans[rt]=ans[ls]+Calc(m+1,r,rs,right[ls]);
    	}
    	void Build(int l,int r,int rt)
    	{
    		if(l==r) {ans[rt]=right[rt]=las[l]; return;}
    		int m=l+r>>1;
    		Build(lson), Build(rson), Update(l,r,m,rt);
    	}
    	void Modify(int l,int r,int rt,int p,int v)
    	{
    		if(l==r) {ans[rt]=right[rt]=v; return;}
    		int m=l+r>>1;
    		if(p<=m) Modify(lson,p,v);
    		else Modify(rson,p,v);
    		Update(l,r,m,rt);
    	}
    }T;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    void Modify(int val,int pos)
    {
    	static std::set<int>::iterator pre,nxt;
    
    	int vp=A[pos];
    	pre=st[vp].lower_bound(pos), --pre;
    	nxt=st[vp].upper_bound(pos);
    	if(nxt!=st[vp].end()) T.Modify(1,n,1,*nxt,*pre);
    	st[vp].erase(pos);
    
    	pre=nxt=st[val].upper_bound(pos), --pre;
    	st[val].insert(pos), T.Modify(1,n,1,pos,*pre);
    	if(nxt!=st[val].end()) T.Modify(1,n,1,*nxt,pos);
    	A[pos]=val;
    }
    
    int main()
    {
    //	freopen("b.in","r",stdin);
    //	freopen("my.out","w",stdout);
    
    	n=read();
    	for(int i=1; i<=n; ++i) st[i].insert(0);
    	for(int i=1,a; i<=n; ++i)
    		a=A[i]=read(), st[a].insert(i), las[i]=las_v[a], las_v[a]=i;
    	T.Build(1,n,1); LL tot=1ll*n*(n+1)>>1;
    	for(int Q=read(); Q--; )
    		if(!read()) printf("%lld
    ",tot-T.ans[1]);
    		else Modify(read(),read());
    
    	return 0;
    }
    

    C 淘汰赛

    题目链接

    生成函数+倍增+常系数线性递推。。

    
    

    考试代码

    A

    #include <cstdio>
    #include <algorithm>
    #define INF 1e14
    #define eps (1e-8)
    typedef long double ld;
    const int N=1e6+5;
    //#define double ld
    int n;
    struct Node
    {
    	double a,p;
    	bool operator <(const Node &x)const{
    		return p>x.p;
    	}
    }A[N];
    double sum[N],sum2[N],Ans,W1,C1,W2,C2;
    
    void Calc1(double x)
    {
    	int l=1,r=n,mid,ans=0;
    	while(l<=r)
    	{
    		mid=l+r>>1;
    		if((ld)x*A[mid].p>=1) ans=mid, l=mid+1;
    		else r=mid-1;
    	}
    	W1=sum[ans], C1=W1-x*sum[ans];
    }
    void Calc2(double x)
    {
    	int l=1,r=n,mid,ans=0;
    	while(l<=r)
    	{
    		mid=l+r>>1;
    		if((ld)x*(1-A[mid].p)>=1) ans=mid, r=mid-1;
    		else l=mid+1;
    	}
    	W2=sum2[ans], C2=W2-x*sum2[ans];
    }
    inline double Get_Ans(double x)
    {
    	Calc2(x); Ans=std::max(Ans,std::min(C1+W2,C2+W1));
    	return std::min(C1+W2,C2+W1);
    }
    inline double Get_Ans2(double x)
    {
    	Calc1(x);
    	double l=0,r=1e7,lmid,rmid;
    	while(r-l>eps)
    	{
    		lmid = l+(r-l)/3, rmid = r-(r-l)/3;
    		if(Get_Ans(lmid)>Get_Ans(rmid)) r=rmid;
    		else l=lmid;
    	}
    	return Get_Ans(l);
    }
    
    int main()
    {
    //	freopen("a2.in","r",stdin);
    //	freopen("a.out","w",stdout);
    
    	scanf("%d",&n);
    	for(int i=1; i<=n; ++i) scanf("%lf%lf",&A[i].a,&A[i].p);
    	std::sort(A+1,A+1+n);
    	for(int i=1; i<=n; ++i) sum[i]=sum[i-1]+A[i].a;
    	for(int i=n; i; --i) sum2[i]=sum2[i+1]+A[i].a;
    
    	double l=0,r=1e7,lmid,rmid;
    	while(r-l>eps)
    	{
    		lmid = l+(r-l)/3, rmid = r-(r-l)/3;
    		if(Get_Ans2(lmid)>Get_Ans2(rmid)) r=rmid;
    		else l=lmid;
    	}
    	printf("%.6lf
    ",Ans);
    
    	return 0;
    }
    

    B

    #include <set>
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 400000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=1e5+5;
    
    int n,A[N];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    namespace Subtask1
    {
    	bool vis[N];
    	inline void Query()
    	{
    		vis[A[n+1]]=1;//n+1
    		LL res=0;
    		for(int i=1; i<=n; ++i)
    		{
    			int j=i;
    			while(!vis[A[j]]) vis[A[j++]]=1;
    			res+=j-i;
    			for(int k=i; k<j; ++k) vis[A[k]]=0;
    		}
    		printf("%lld
    ",res);
    	}
    	void Main()
    	{
    		int Q=read();
    		for(int i=1; i<=Q; ++i)
    			if(!read()) Query();
    			else A[read()]=read();
    	}
    }
    namespace Subtask2
    {
    	std::set<int> pos[1005];
    }
    
    int main()
    {
    //	freopen("b2.in","r",stdin);
    //	freopen("my.out","w",stdout);
    
    	n=read();
    	for(int i=1; i<=n; ++i) A[i]=read();
    	if(n<=1000) {Subtask1::Main(); return 0;}
    
    	return 0;
    }
    

    C

    #include <cstdio>
    #include <cassert>
    #include <algorithm>
    #define gc() getchar()
    #define mod (998244353)
    typedef long long LL;
    const int N=1e6+5;
    
    LL n; int m;
    
    namespace Subtask1
    {
    	#define N 1005
    	int f[N][N],ans[N][N],pw[N];
    	bool vis[N][N];
    	#undef N
    	int DFS(int n,int m)
    	{
    		if(!m) return n==1;
    //		if(n<pw[m]) return 0;
    		if(vis[n][m]) return ans[n][m];
    		LL res=0;
    		for(int i=pw[m-1],lim=n>>1; i<=lim; ++i)
    			res+=1ll*DFS(i,m-1)*f[n][i]%mod;
    		vis[n][m]=1;
    		return ans[n][m]=(int)(res%mod);
    	}
    	void Main()
    	{
    		for(int i=0; i<=m; ++i) pw[i]=1<<i;
    		f[2][1]=f[3][1]=1;
    		for(int i=4; i<=n; ++i)
    			for(int j=1,lim=i>>1; j<=lim; ++j)
    				f[i][j]=f[i-1][j]+f[i-2][j-1], f[i][j]>=mod&&(f[i][j]-=mod);
    		printf("%d
    ",DFS(n,m));
    	}
    }
    
    int main()
    {
    //	freopen("c2.in","r",stdin);
    //	freopen(".out","w",stdout);
    
    	scanf("%lld%d",&n,&m);
    	if(n<=1003) {Subtask1::Main(); return 0;}
    	putchar('0');//输出1 13分。。
    	
    
    	return 0;
    }
    
  • 相关阅读:
    Android状态栏和导航栏
    ScrollView小记
    iOS本地推送
    java-集合框架-泛型1
    java-集合框架4---foreach使用--for的增强使用
    java-集合框架3-迭代器的使用
    JAVA-集合框架2
    Number 数据类型转化 NaN 函数isNaN
    数据类型分类
    VScode 插件推荐安装
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9443500.html
Copyright © 2011-2022 走看看