• 2018-2019 Winter Petrozavodsk Camp, Oleksandr Kulkov Contest 1 解题报告


    E


    签到题,看起来像是博弈论,其实仔细思考后发现,一个石子堆为偶数一定给两人贡献相同,实际上对答案有贡献的是奇数堆,那么只要统计奇数堆的个数就行了。


    #include <bits/stdc++.h>
    
    using namespace std;
    
    int input(){
    	int x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    int n;
    int a,Ans,cnt;
    
    int main(){
    	n=input();
    	for(int i=1;i<=n;i++){
    		a=input();
    		if(a%2==1) cnt++;
    		Ans+=a/2;
    	}
    	Ans+=cnt%2? cnt/2+1:cnt/2;
    	printf("%d
    ",Ans);
    }
    

    K


    签到题,随便手玩一下不难发现计算答案时除去(a_1)(a_2)之间的符号无法改变,其他项之间都能找到相反的符号排列方式。


    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    const ll mod=1e9+7;
    const int N=4007;
    
    int a[N];
    
    int main(){
    	int n=input();
    	for(int i=1;i<=n;i++){
    		a[i]=input();
    	}
    	printf("%d
    ",(a[1]-a[2]+mod)%mod);
    }
    

    H


    首先策略肯定是:存在某个阈值k,使得小于等于k时就给对面,否则自己拿着。然后设期望差值为s。然后讨论第一轮的数i是啥,如果i小于等于k,那么最后的ans=s-i,因为第二轮先手不变,期望值不变。如果i大于k,那么最后的ans=i-s,因为先后手交换,期望值取反。所以有(E(Ans)=frac{1}{m}(sum_{i=1}^{k}(s-i)+sum_{i=k+1}^{m}(i-s)))。这个式子肯定把(k)设为(ans)的时候取最大值所以有(E(Ans)=frac{1}{m}(sum_{i=1}^{m}|Ans-i|))。(官方给的题解表达方式是(dp_n=frac{1}{m}(sum_{i=1}^{m}max(dp_{n-1}-i,i-dp_{n-1}))=frac{1}{m}(sum_{i=1}^{m}|dp_{n-1}-i|))

    要解这个东西我们可以先考虑二分答案的整数部分,然后再计算答案。

    我们不妨设答案为(x)。那么有:

    [x=frac{1}{m}(sum_{i=1}^{lfloor x floor}(x-i)+sum_{i=lfloor x floor+1}^{m}(i-x))\ mx=xlfloor x floor-frac{lfloor x floor(lfloor x floor+1)}{2}+frac{(m+lfloor x floor+1)(m-lfloor x floor)}{2}+(lfloor x floor-m)x\ mx=(2lfloor x floor-m)x-frac{2lfloor x floor^2+2lfloor x floor-m^2-m}{2}\ 2(m-lfloor x floor)x=frac{m^2-lfloor x floor^2}{2}+frac{m-lfloor x floor}{2}-frac{lfloor x floor^2+lfloor x floor}{2}\ x=frac{m+lfloor x floor+1}{4}-frac{lfloor x floor(lfloor x floor+1)}{4(m-lfloor x floor)} ]

    所以我们可以通过(lfloor x floor)计算出答案。然后要得到答案可以通过二分用(mx=sum_{mid}+sum_{m-mid})来获得(lfloor x floor)


    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    const ll mod=1e9+7;
    
    ll powmod(ll a,ll b){
    	ll res=1;
    	while(b){
    		if(b&1) res=res*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return res;
    }
    
    ll sum(ll x){
    	return x*(1+x)/2;
    }
    
    int main(){
    	int T=input();
    	while(T--){
    		ll m=input();
    		ll l=1,r=m;
    		while(l<r){
    			ll mid=(l+r+1)>>1;
    			if(sum(mid-1)+sum(m-mid)>=mid*m) l=mid;
    			else r=mid-1;
    		}
    		ll x1=(m+l+1)%mod;
    		ll x2=l*(l+1)%mod*powmod((m-l)%mod,mod-2)%mod;
    		ll Ans=((x1-x2+mod)%mod*((mod+1)/4))%mod;
    		printf("%lld
    ",Ans);
    	}
    }
    

    F


    把边按权值排序从大到小加入图中,如果加入树边,且边的端点已经连通,则包含这两端点连通块不合法;如果加入图边,且两点还未连通,那么包含这条边两端点的连通块也不合法。考虑到边权有相同的情况,需要把相同的边一并加入图中。


    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    #define pb push_back
    
    const int N=1e5+7;
    
    struct bcj{
    	int fa[N],rank[N],col[N];
    	int find(int x){
    		if(fa[x]==x) return x;
    		int t=find(fa[x]);
    		if(col[fa[x]]||col[t]) col[x]=1;
    		fa[x]=t;
    		return t;
    	} 
    	void merge(int x,int y){
    		x=find(x);y=find(y);
    		if(col[x]<col[y]) swap(x,y);
    		fa[x]=y;
    		if(x!=y) rank[y]+=rank[x];
    	}
    	
    }t,g;
    
    struct edge{
    	int t,u,v,w;
    }e[N*2];
    int n,m;
    
    bool cmp(edge a,edge b){
    	if(a.w!=b.w) return a.w>b.w;
    	if(a.t!=b.t) return a.t>b.t;
    	return 0;
    }
    
    int main(){
    	n=input(),m=input();
    	for(int i=1;i<=m;i++){
    		e[i].t=input(),e[i].u=input(),e[i].v=input(),e[i].w=input();
    	}
    
    	for(int i=1;i<=n;i++){
    		g.fa[i]=t.fa[i]=i;
    		g.rank[i]=t.rank[i]=1;
    	}
    
    	sort(e+1,e+1+m,cmp);
    
    	for(int i=1;i<=m;){
    		int j=i;
    		while(j<=m&&e[i].w==e[j].w){
    			if(e[j].t==1){
    				g.merge(e[j].u,e[j].v);
    				t.merge(e[j].u,e[j].v);
    			}else g.merge(e[j].u,e[j].v);
    			j++;
    		}
    
    		for(int k=i;k<j;k++){
    			int t1=g.find(e[k].u),t2=t.rank[t.find(t1)];
    			if(t2!=g.rank[t1]) g.col[t1]=1;
    		}
    		i=j;
    	}
    
    	vector <int> ans;
    	for(int i=1;i<=n;i++){
    		g.find(i);
    		if(g.col[i]==0&&g.col[g.fa[i]]==0) ans.pb(i);
    	}
    	printf("%d
    ",ans.size());
    	for(int i=0;i<ans.size();i++){
    		printf("%d%c",ans[i],i==ans.size()-1? '
    ':' ');
    	}
    }
    

  • 相关阅读:
    TeamViewer14
    mysql 导出表结构和表数据 mysqldump用法
    虚拟机中不能上外网
    Mysql初始化root密码和允许远程访问
    常用sql语句
    查看连接MYSQL数据库的IP信息
    设置linux下shell显示不同颜色的字体
    常用mysql导入导出数据的命令
    spring boot 以jar的方式启动常用shell脚本
    idea的properties文件乱码问题解决
  • 原文地址:https://www.cnblogs.com/-aether/p/12525182.html
Copyright © 2020-2023  润新知