题解 CF1710C XOR Triangle

我们令 \(x=a\ \text{xor}\ b\)\(y=b\ \text{xor}\ c\)\(z=c\ \text{xor}\ a\)。容易发现 \(x,y,z\) 满足 \(x\ \text{xor}\ y\ \text{xor}\ z=0\)。我们考虑他们什么时候可以构成三角形。结论是:当且仅当存在其中两个数 \(x,y\) 满足 \(x\ \text{and}\ y=0\),不满足构成三角形。下面简单说明一下。

  • 充分:当 \(x\ \text{and}\ y=0\) 时,\(x\)\(y\) 不会同时有一位是 \(1\)。所以 \(x\ \text{xor}\ y=x+y=z\),因此不满足。
  • 必要:任意两个数的与都不等于 \(0\),我们不妨三个数大小顺序 \(x>y>z\)。由于 \(y\ \text{and}\ z>0\),那么 \(y,z\) 至少有一位同时是 \(1\),所以 \(x=y\ \text{xor}\ z<y+z\)。也就满足构成三角形。

于是我们考虑数位 DP。从高位到低位做,记三个变量表示当前 \(a,b,c\) 是否满足已填的位都与 \(n\) 相同的限制,再记三个变量分别表示 \(x\ \text{and}\ y\)\(y\ \text{and}\ z\)\(z\ \text{and}\ x\) 是否仍为 \(0\)。转移是平凡的,枚举 \(a,b,c\) 这一位填了什么,更新上述六个变量即可。

这样做的复杂度是 \(O(2^9n)\)

const int N=200005;
int n,m; 
char s[N];
ll dp[N][2][2][2][2][2][2];

ll dfs(int u,bool a,bool b,bool c,bool x,bool y,bool z)
{
	if (u==n+1)
	{
		if (x&&y&&z) return 1;
		return 0;
	}
	if (dp[u][a][b][c][x][y][z]!=-1) return dp[u][a][b][c][x][y][z];
	ll res=0;
	for (int i=0;i<=1;i++)
	{
		if (a&&i>s[u]-'0') continue;
		for (int j=0;j<=1;j++)
		{
			if (b&&j>s[u]-'0') continue;
			for (int k=0;k<=1;k++)
			{
				if (c&&k>s[u]-'0') continue;
				res=(res+dfs(u+1,a&(s[u]-'0'==i),b&(s[u]-'0'==j),c&(s[u]-'0'==k),x|((i^j)&(j^k)),y|((i^k)&(j^k)),z|((i^k)&(j^i))))%mod;
			}
		}
	}
	dp[u][a][b][c][x][y][z]=res;
	return res;
}

int main()
{
	cin >> (s+1);
	n=strlen(s+1);
	memset(dp,-1,sizeof(dp));
	cout << dfs(1,1,1,1,0,0,0);
	return 0;
}

posted @ 2022-07-27 15:43  Little09  阅读(215)  评论(0)    收藏  举报