Codeforces Round #507 div2 DE题解

C. Timetable

题意:还没读懂.....

D. Subway Pursuit

题意:交互题,你要求一个点的位置,这个点在1到n之中,每次可以移动至多k步,你每次可以询问系统一个区间 [ L , R ],系统会告诉你这个点在该时刻是否在区间内,要求至多用4500次求出这个点的坐标。

思路:先用二分缩小目标点的可确定区间,直到区间缩小的一定值后,随机询问某个点,看答案是否是它,若不是就扩大确定范围继续二分即可。由于 k 的值最大不过10,因此可以用随机算法而且可以在较短的询问次数内随机求出目的点位置。

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
char s[5];
ll n,k;
int ss(ll l,ll r)
{
	printf("%I64d %I64d\n",l,r);
	cin>>s;
	if(s[0]=='Y')return 1;
	return 0;
}
int main()
{
	srand(23333);
	cin>>n>>k;
	ll l=1,r=n;
	while(1)
	{
		l=max(1ll,l-k);
		r=min(n,r+k);
		if(r-l<=4*k)
		{
			ll w=rand()%(r-l+1)+l;
			if(ss(w,w))return 0;
		}
		else
		{
			ll m=(l+r)/2;
			if(ss(l,m))r=m;
			else l=m+1;
		}
	}
}

E. Network Safety

题意:给你一个n个点,m条边的无向图,每个点有权值,给你一个范围[ 0 , 2^k-1 ],你可以从这个范围内选择一个数 x,然后从图中选择任意一些点的集合 s,使得集合内所有点都异或 x 后,原图每条边连接的两个点的值都不相等(保证原始图每条边连接的两个点权值不同),求有多少种组合( x ,s )。

思路:对于每条边连接的 u v,我设边权为wi=au^av,如果点u或点v只有一个点异或了wi,就非法,因此我先排除掉所有的wi(假设总共有cnt个不同的wi),对于每个点,我可以选择加入集合或者不加,因此有2^n中情况,加入集合后 x 有2^k-cnt个取值,因此一共有(2^k-cnt)*2^n种组合,但是对于边权为 wi 的边,我可以把u v看成同一个点,要么同时异或wi,要么都不异或,因此还漏一些组合,之前的数再加上现在漏掉的数就是答案了。

#include<cstdio>
#include<vector>
#include<map>
using namespace std;
const int maxn=5e5+10,mod=1e9+7;
typedef long long ll;
map<ll,int>mp;
struct node
{
	int x,y;
	node(int a,int b){x=a,y=b;}
};
vector<node>G[maxn];
ll a[maxn],p[maxn],par[maxn];
void init(int n)
{
	p[0]=1;
	for(int i=1;i<=n;i++)
	p[i]=p[i-1]*2%mod,par[i]=i;
}
int find(int x)
{
	if(par[x]!=x)
	par[x]=find(par[x]);
	return par[x];
}
int Union(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx!=fy)
	{
		par[fx]=fy;
		return 1;
	}
	return 0;
}
int main()
{
	int n,m,k,u,v,cnt=0;
	scanf("%d%d%d",&n,&m,&k);
	init(n);
	for(int i=1;i<=n;i++)
	scanf("%I64d",&a[i]);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		ll x=a[u]^a[v];
		if(!mp[x])mp[x]=++cnt;
		G[mp[x]].push_back(node(u,v));
	}
	ll ans=((1ll<<k)-cnt)%mod*p[n]%mod;
	for(int i=1;i<=cnt;i++)
	{
		int s=n;
		for(int j=0;j<G[i].size();j++)
		if(Union(G[i][j].x,G[i][j].y))
		s--;
		ans=(ans+p[s])%mod;
		for(int j=0;j<G[i].size();j++)
		{
			int x=G[i][j].x,y=G[i][j].y;
			par[x]=x,par[y]=y;
		}
	}
	printf("%I64d\n",ans);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值