其他分享
首页 > 其他分享> > 【Luogu1092】虫食算

【Luogu1092】虫食算

作者:互联网

Source and Judge

NOIP2004 提高组 T4
Luogu1092
Caioj1519

Problem

【Brief description】
所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,
需要我们根据剩下的数字来判定被啃掉的字母。
来看一个简单的栗子:

123
 43#9865#045+  8468#6633=44445509678


其中#号代表被虫子啃掉的数字。
根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。

现在,我们对问题做两个限制:
首先,我们只考虑加法的虫食算。
这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。

其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,
我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。
如果这个算式是N进制的,
我们就取英文字母表的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字,
但是这N个字母并不一定顺序地代表0到N-1。
输入数据保证N个字母分别至少出现一次。
123
 BADC+CBDA DCCC


上面的算式是一个4进制的算式。
很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。
你的任务是,对于给定的N进制加法算式,
求出N个不同的字母分别代表的数字,使得该加法算式成立。
输入数据保证有且仅有一组解.
【Input】
包含四行。
第一行有一个正整数N,
后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。
这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。
【Output】
包含一行。在这一行中,应当包含唯一的那组解。
解是这样表示的:
输出N个数字,分别表示A,B,C……所代表的数字,
相邻的两个数字用一个空格隔开,不能有多余的空格。
【Limited conditions】
N<=26
【Sample input】
5
ABCED
BDACE
EBBAA
【Sample output】
1 0 3 4 2
【Sample explanation】

Record

1h

Analysis1

请先思考后再展开

先打了个暴力,想着数据可能水【其实的确没有极限数据】
但依然TLE,但已经剪枝了
然后跟着题解,发现可以不递推进位,减更多
这时候还是差一点,然后就是一个神奇的玄学操作了:
重新编号(从后往前),dfs决断的时候编号从大到小
我一开始想着,这是为了搞掉首位进位(这个也是跟题解学的)
那既然如此编号从前往后,dfs的时候从小到大也一样吧
结果差距是几十倍??

考场上绝对不能这么玩,会死的很惨

Code1

请先思考后再展开
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
//****************头文件****************#include<cstring>#include<cmath>#include<queue>#include<vector>#include<set>#include<string>#include<map>#include<iostream>#include<algorithm>#ifdef WIN32#define BIGN "%I64d"#else#define BIGN "%lld"#endifusing namespace std;typedef long long ll;int (int x,int y) {return x>y?x:y;}int mymin(int x,int y) {return x<y?x:y;}//****************全局常量****************const int INF=0x3f3f3f3f;//****************全局定义****************int n;int a[30];bool used[30];int jia1[30],jia2[30],he[30];//****************实现****************bool finaljudge(){	int jw=0;	for(int i=1;i<=n;i++)	{		int x=a[jia1[i]],y=a[jia2[i]],z=a[he[i]];		if( (x+y+jw)%n!=z ) return 0;		jw=(x+y+jw)/n;	}	return 1;}bool check(){	if(a[jia1[n]]+a[jia2[n]]>=n) return 0;	for(int i=1;i<=n;i++)//从后往前	{		int x=a[jia1[i]],y=a[jia2[i]],z=a[he[i]];		if(x<0 or y<0 or z<0) continue;//残缺		if( (x+y)%n!=z and (x+y+1)%n!=z ) return 0;	}	return 1;}int nxt[30];//新编号-Importantvoid Print(){	for(int i=1;i<=n;i++) printf("%d ",a[i]);	exit(0);}void dfs(int x){	if(x>n)	{		if(finaljudge()) Print();		return;	}		//for(int i=0;i<=n-1;i++) 玄学操作    for(int i=n-1;i>=0;i--)		if(used[i]==0)		{			a[ nxt[x] ]=i;			if(check())			{				used[i]=1;				dfs(x+1);				used[i]=0;			}			a[ nxt[x] ]=-1;		}}int cnt=0;//新编号-Importantvoid putnxt(int x){	if(used[x]==0)	{		used[x]=1;//借用		nxt[++cnt]=x;	}}//****************主函数****************char ch[30];int main(){	scanf("%d",&n);	scanf("%s",ch+1);for(int i=n;i>=1;i--) jia1[n-i+1]=ch[i]-'A'+1;	scanf("%s",ch+1);for(int i=n;i>=1;i--) jia2[n-i+1]=ch[i]-'A'+1;	scanf("%s",ch+1);for(int i=n;i>=1;i--) he[n-i+1]=ch[i]-'A'+1;		for(int i=1;i<=n;i++)//新编号-Important	{		putnxt(jia1[i]);		putnxt(jia2[i]);		putnxt(he[i]);	}		memset(used,0,sizeof(used));	memset(a,-1,sizeof(a));	dfs(1);}

Analysis2

请先思考后再展开

并没有看懂的正解:
https://blog.csdn.net/JeremyGJY/article/details/50611568
https://blog.csdn.net/outer_form/article/details/50611820

Code2

请先思考后再展开
12

原文:大专栏  【Luogu1092】虫食算


标签:ch,数字,Luogu1092,食算,int,used,算式,include
来源: https://www.cnblogs.com/wangziqiang123/p/11643295.html