AT_abc347_d 题解

纯脑掺题目。

最开始的思路很飞舞我就不写了。

首先先是 -1 的情况(\(c\)\(C\)\(popcount\)):

  • \(a+b+c\equiv 1\pmod 2\)
  • \(a+b+c\gt 120\)
  • \(a\gt b+c,b\gt c+a,c\gt a+b\).

第一个很容易想到。

第二个是因为题中 \(X,Y\) 的上限限制。

第三个是因为很明显搞不了。

后面的构造:

为方便,让 \(n_{i,j}\) 代表满足 \(X\)\(Y\) 的二进制表示的第 \(k\) 位分别是 \(i\)\(j\)\(k\) 的个数。

\(S_0\) 是由 \(n_{0,0}\)\((0,0)\)\(n_{1,1}\)\((1,1)\) 组成的序列,\(S_1\) 是由 \(n_{0,1}\)\((0,1)\)\(n_{1,0}\)\((1,0)\) 组成的序列。(\((i,j)\) 表示 \(X\) 这位选 \(i\)\(Y\) 这位选 \(j\)

对于二进制下 \(C\) 的每一位,设 \(p\) 为这位的数字。(位从后向前进行递减)

首先,删掉 \(S_p\) 的最后一个二元组,代表它被使用过了。

\((x,y)\) 为刚刚删掉的元素,并将 \(X\)\(Y\) 的这位分别设为 \(x\)\(y\)

然后,我们根据以上定义以及题目,发现:

  • \(popcount(X)=a\iff n_{1,0}+n_{1,1}=a\)
  • \(popcount(Y)=b\iff n_{0,1}+n_{1,1}=b\)
  • \(X\oplus Y=C\implies n_{1,0}+n_{0,1}=popcount(C)\)

又因为 \(\sum n_{i,j}=60\)(总方案数就是整体),于是我们可以推出:

\[n_{0,0}=60-\frac{a+b+c}{2} \]

\[n_{0,1}=\frac{-a+b+c}{2} \]

\[n_{1,0}=\frac{a-b+c}{2} \]

\[n_{1,1}=\frac{a+b-c}{2} \]

没了。

#include<stdio.h>
#include<bits/stdc++.h>
#define N 1000010
#define MOD 998244353
#define esp 1e-8
#define INF 999999999999999999
#define LL long long
#define rep(i,a,b,g) for(LL i=a;i<=b;i+=g)
#define rem(i,a,b,g) for(LL i=a;i>=b;i-=g)
#define repn(i,a,b,g) for(LL i=a;i<b;i+=g)
#define remn(i,a,b,g) for(LL i=a;i>b;i-=g)
#define pll pair<LL,LL>
#define mkp(x,y) make_pair(x,y)
#define i128 __int128
#define lowbit(x) ((x)&(-(x)))
#define lc (u<<1)
#define rc (u<<1|1)
using namespace std;
void read(i128 &x)
{
	i128 f=1;
	x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
void writing(i128 x)
{
	if(x>=10)writing(x/10);
	putchar(x%10+'0');
}
void write(i128 x)
{
	if(x<0)
	{
		cout<<'-';
		x=-x;
	}
	writing(x);
}
LL a,b,C,c;
LL popcount(LL x)
{
	LL sum=0;
	while(x)
	{
		if(x&1)sum++;
		x/=2;
	}
	return sum;
}
int main()
{
	cin>>a>>b>>C;
	c=popcount(C);
	if((a+b+c)%2!=0||a+b+c>120||a>b+c||b>c+a||c>a+b)
	{
		cout<<-1<<endl;
		return 0;
	}
	LL n00=60-(a+b+c)/2;
	LL n01=(-a+b+c)/2;
	LL n10=(a-b+c)/2;
	LL n11=(a+b-c)/2;
	LL bx,by,nb;
	bx=by=0;
	nb=60;
	while(nb--)
	{
		bx*=2;
		by*=2;
		if(1&(C>>nb))
		{
			if(n10)
			{
				bx++;
				n10--;
			}
			else
			{
				by++;
				n01--;
			}
		}
		else
		{
			if(n00)
			{
				n00--;
			}
			else
			{
				bx++;
				by++;
				n11--;
			}
		}
	}
	cout<<bx<<' '<<by<<endl;
	return 0;
}
posted @ 2024-03-31 00:07  cppom  阅读(28)  评论(0编辑  收藏  举报