Codeforces Round #563 (Div. 2)

A.排序即可
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn=10010;
int n;
long long a[maxn],sum[maxn];
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=2*n;i++) scanf("%lld",&a[i]);
	sort(a+1,a+2*n+1);	
	for (int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i];
	if (2ll*sum[n]==sum[2*n]) return printf("-1\n"),0;
	for (int i=1;i<=2*n;i++) printf("%lld ",a[i]);
return 0;
}

B.将奇数偶数分开考虑,只有偶数和奇数之间可以做交换

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn=100010;
int n,a[maxn],b[maxn],c[maxn],ans[maxn],pb,pc,ppb,ppc;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
		if (a[i]&1) b[++pb]=a[i];else c[++pc]=a[i];
	}
	if (pb) sort(c+1,c+pc+1);
	if (pc) sort(b+1,b+pb+1);
	ppb=ppc=1;
	for (int i=1;i<=n;i++)
	if (ppb==pb+1) ans[i]=c[ppc++];
	else if (ppc==pc+1) ans[i]=b[ppb++];
	else {if (b[ppb]<c[ppc]) ans[i]=b[ppb++];else ans[i]=c[ppc++];}
	for (int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}

C.线性筛出所有因子,具有相同因子的填一样的数

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
const int maxn=100010;
int n,ans[maxn],p,prime[maxn],cnt;
bool f[maxn];
int main()
{
	scanf("%d",&n); p=1; memset(f,1,sizeof f);
	f[0]=f[1]=0;
	for (int i=2;i<=n;i++)
	{
		if (f[i]) prime[++cnt]=i;
		for (int j=1;j<=cnt && 1ll*i*prime[j]<=n;j++)
		{
			f[i*prime[j]]=0;
			if (i%prime[j]==0) break;
		}
	}
	for (int i=1;i<=cnt;i++)
	{
		for (int j=prime[i];j<=n;j+=prime[i]) if (!ans[j]) ans[j]=p;
		p++;
	}
	for (int i=2;i<=n;i++) printf("%d ",ans[i]);
return 0;
}

D.将每个位置的数看做是a^b,那么任意连续子段异或就变成了x^y,那么就变成了构造一个数列,使得两两互不相同,且异或不为x,然后真实序列就是这个序列的相邻项异或

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <set>
using namespace std;
const int maxn=1000010;
int n,x,ans[maxn],p[20],now;
set<int>s;
int main()
{
	scanf("%d%d",&n,&x); 
	p[0]=1; for (int i=1;i<=n;i++) p[i]=p[i-1]*2;
	if (x>=p[n])
	{
		printf("%d\n",p[n]-1);
		for (int i=1;i<=p[n]-1;i++) printf("%d ",i^(i-1));
		return 0;
	}
	printf("%d\n",p[n-1]-1); if (n==1) return 0;
	ans[0]=0; int pp=1; if (x==1) pp=2;
	s.insert(x);
	for (int i=1;i<=p[n-1]-1;i++) 
	{
		ans[i]=pp; s.insert(pp^x); pp++;
		while (s.find(pp)!=s.end()) ++pp;
	}
	for (int i=1;i<=p[n-1]-1;i++) printf("%d ",ans[i]^ans[i-1]);
return 0;
}

E.dp[i][j][k]表示当前放到第i个位置,gcd的因子有j个2,k个3的方案数,转移的时候分三种方法转移:

   1.dp[i+1][j][k]=(dp[i+1][j][k]+1ll*dp[i][j][k]*(calc(j,k)-i))%mo;

   2.dp[i+1][j-1][k]=(dp[i+1][j-1][k]+1ll*dp[i][j][k]*(calc(j-1,k)-calc(j,k)))%mo;

   3.dp[i+1][j][k-1]=(dp[i+1][j][k-1]+1ll*dp[i][j][k]*(calc(j,k-1)-calc(j,k)))%mo;

calc(x,y)计算1~n之间有多少个数的因子里有x个2,y个3

#include <iostream>
using namespace std;
const int mo=1e9+7;
const int maxn=1000002;
int n,t;
int dp[maxn][21][2];
int calc(int a,int b){return n/((1<<a)*(b?3:1));}
int main()
{
	scanf("%d",&n); int p=0; while ((1<<(p+1))<=n) p++;
	dp[1][p][0]=1; if (((1<<(p-1))*3)<=n) dp[1][p-1][1]=1;
	for (register int i=1;i<n;i++)
	{
	 for (register int j=0;j<=p;j++)
	  for (register int k=0;k<=1;k++)
	  {
	  	dp[i+1][j][k]=(dp[i+1][j][k]+1ll*dp[i][j][k]*(calc(j,k)-i))%mo;
	  	if (j) dp[i+1][j-1][k]=(dp[i+1][j-1][k]+1ll*dp[i][j][k]*(calc(j-1,k)-calc(j,k)))%mo;
	  	if (k) dp[i+1][j][k-1]=(dp[i+1][j][k-1]+1ll*dp[i][j][k]*(calc(j,k-1)-calc(j,k)))%mo;
	  }
	}
	printf("%d\n",dp[n][0][0]);
return 0;
}

F.树剖之后每次在重链头上询问方向(s),在重链尾部询问距离(d),这样重链有log条,询问次数至多2log次

  注意1:在1号点先问一次距离,每次用这个距离来判断当前重链头是不是要找的点(若是就直接输出而不是询问方向)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=200010;
int n,m,st[maxn<<1],nt[maxn<<1],to[maxn<<1],topt;
int si[maxn],rem[maxn],top[maxn],down[maxn],dep[maxn],fa[maxn],mm[maxn];
int dfn_num,dfn[maxn],line[maxn],d1,d2,ff[30][maxn],de;
bool f[maxn],ok;
inline void add(int x,int y){to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}
void dfs1(int x,int dd)
{
	f[x]=1; dep[x]=dd; si[x]=1; int p=st[x],ma=0;
	while (p)
	{
		if (!f[to[p]])
		{
			dfs1(to[p],dd+1); si[x]+=si[to[p]]; fa[to[p]]=x; ff[0][to[p]]=x;
			if (si[to[p]]>ma) {ma=si[to[p]]; rem[x]=to[p];}
		}
		p=nt[p];
	}
}
void dfs2(int x)
{
	f[x]=1; if (rem[fa[x]]==x) top[x]=top[fa[x]];else top[x]=x;
	if (mm[top[x]]<dep[x]) {mm[top[x]]=dep[x]; down[top[x]]=x;} 
	int p=st[x]; if (rem[x]) dfs2(rem[x]);
	while (p)
	{
		if (!f[to[p]]) dfs2(to[p]);
		p=nt[p];
	}
}
int find(int x,int k)
{
	int p=0; if (k==0) return x;
	while ((1<<(p+1))<=k) p++;
return find(ff[p][x],k-(1<<p));
}
void work(int x,int dis)
{
	if (ok) return;
	if (x==1) {printf("d %d\n",x); fflush(stdout); scanf("%d",&d1);  de=d1;}else d1=dis;
	if (d1==0) {printf("! %d\n",x); ok=1; return;}
	if (d1==1)
	{
		printf("s %d\n",x); fflush(stdout); scanf("%d",&d1);
		printf("! %d\n",d1); fflush(stdout); ok=1; return;
	}
	printf("d %d\n",down[x]); fflush(stdout); scanf("%d",&d2);
	if (d2==0) {printf("! %d\n",down[x]); fflush(stdout); ok=1; return;}
	if (d1+d2==dep[down[x]]-dep[x]) 
	 {printf("! %d\n",find(down[x],dep[down[x]]-de)); fflush(stdout); ok=1; return;}
	else 
	{
		int xx=find(down[x],dep[down[x]]-de+(d1+d2-(dep[down[x]]-dep[x]))/2);
		printf("s %d\n",xx); fflush(stdout); int now; scanf("%d",&now);
		work(now,de-dep[now]);
	}
} 
int main()
{
	scanf("%d",&n);
	for (int i=1;i<n;i++) 
	{
		int xx,yy; scanf("%d%d",&xx,&yy);
		add(xx,yy); add(yy,xx);
	}
	dfs1(1,0); memset(f,0,sizeof f); dfs2(1);
	for (int i=1;i<=20;i++)
 	 for (int j=1;j<=n;j++) ff[i][j]=ff[i-1][ff[i-1][j]]; 
	work(1,0);
return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值