专栏文章

题解:P2456 [SDOI2006] 二进制方程

P2456题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipkni73
此快照首次捕获于
2025/12/03 13:33
3 个月前
此快照最后确认于
2025/12/03 13:33
3 个月前
查看原文
感觉这题像并查集模板
大致思路:先将左右两侧的字符串对齐,每一位用并查集合并,最后寻找有 ansans 位的数不受其他数影响,答案即为 2ans2^{ans}

对齐

首先将题目第二行所给长度记作 varivar_i,每个变量拉伸为 varivar_i 长度。
eg. 以样例一为例,可拉伸为如下形式
1b1b21a1a2a3a4|1|b_1|b_2|1|\\ |a_1|a_2|a_3|a_4|

合并

由题意我们可以知道,等号两边对印位置的数字相等,因此我们可以用并查集 fif_i 将它们关联起来。
eg. 同样以样例一为例, fif_i 对印关系如下。
f0f1f2f3f4f5f6f70 1 a1a2a3a4b1b2|f_0|f_1|f_2|f_3|f_4|f_5|f_6|f_7|\\ |0\ |1\ |a_1|a_2|a_3|a_4|b_1|b_2|
然后,我们按位让等号两边对应位相等(合并并查集,最好将根节点较大的合并到较小的,这样比较方便 [doge]),可得到如下的 fif_i
f0f1f2f3f4f5f6f7 0  1  1  3  4  1  3  4 |f_0|f_1|f_2|f_3|f_4|f_5|f_6|f_7|\\ |\ 0\ |\ 1\ |\ 1\ |\ 3\ |\ 4\ |\ 1\ |\ 3\ |\ 4\ |

答案

当我们把等号两侧的信息合并为一个并查集 fif_i 后,显然只有 fi=if_i=i 的位才不会受到其他位的影响,并且与其他有相同性质的位相互独立。 fif_i 中除 f0f_0f1f_1 以外,共 ansans 位符合 fi=if_i=i 的性质。
通过乘法原理,答案即为 2ans2^{ans}

Code

CPP
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define f(n) for(int i=1;i<=n;i++)
int var[27],n,f[270010],ans;
string l,r;
string cl(string x)//拉伸等号两侧 
{
	string ls;
	ls.clear();
	f(x.length())
		if(x[i-1]=='1'||x[i-1]=='0')ls+=x[i-1];
		else for(int j=1;j<=var[x[i-1]-'a'];j++)ls+=x[i-1];
	return ls;
}
int fd(int now)//合并并查集 
{
	if(f[now]==now)return now;
	return f[now]=fd(f[now]);
}
void d(int now,int nw)//将每个var转为记录对应变量在f中第一位的位置 
{
	if(now==n+1)
	{
		n=nw-1;//end
		return;
	}
	d(now+1,var[now]+nw);
	var[now]=nw;
}
int v(char c)//统一处理字符到f的转换 
{
	if(c=='1'||c=='0')return c-'0';
	return var[c-'a'];
}
int high[1000001]={0,1},hl=1;//高精度 
int main()
{
	f(270009)f[i]=i;
	ios::sync_with_stdio(0);
	cin>>n;
	f(n)cin>>var[i-1];
	cin>>l>>r;
	l=cl(l);
	r=cl(r);
	d(0,2);
	//下方为 
	int ls=0,rs=0,lf,rf;
	//ls记录当前位是对应变量中的第几位,rs同理但是记录等号右侧 
	f(l.length())
	{
		if(i>1)
		{
			if(l[i-1]==l[i-2])ls++;
			else ls=0;
			if(r[i-1]==r[i-2])rs++;
			else rs=0;
		}
		lf=fd(v(l[i-1])+ls);
		rf=fd(v(r[i-1])+rs);
		//lf,rf为两方所在并查集根节点 
		if(lf+rf==1)//以防万一存在无解情况 
		{
			cout<<0;
			return 0;
		}
		if(lf<rf)f[rf]=f[lf];
		else f[lf]=f[rf];
	}
	//计算独立位的数量 
	f(n-1)if(f[i+1]==i+1)ans++;
	//高精度 
	int jc;
	f(ans)
	{
		jc=0;
		for(int j=1;j<=hl;j++)
    	{
			high[j]=high[j]*2+jc;
			jc=high[j]/10;
			high[j]%=10;
		}
		if(jc!=0)high[++hl]=jc;
	}
	f(hl)cout<<high[hl-i+1];
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...