题解 P2702 【[NOI2003]木棒游戏】
一道简单的模拟题
首先我们来看一下题面
??? 图呢
根据我们的生活经验,我们知道
首先我们发现,题目中不能移动构成运算符(+、-、=)的木棒 ,因此我们不管怎么移动数字的木棒,这个数的加、减和位数是不变的。我们如果把所有的数字都按照位数拆开来,以样例为例
11+77=34
变成
1*10+1*1+7*10+7*1=3*10+4*1
那么不管数字怎么变,它后面乘的多少是不会变的,因此我们可以提前处理好。然而在等号两边让我们看起来很不爽,反正符号不会变,我们可以通过初中知识移项将其全部移到一遍就ok了
1*10+1*1+7*10+7*1-3*10-4*1=0
那我们现在只需要通过更改上式中任意两个第一项使其成立就做完了
我们知道
由于我比较懒,用了一种常数较大的
对于一个数字,选择用状压去描述,如果有第
当对第
具体实现可以参考代码
#include<bits/stdc++.h>
char ch[2000];
const int n[10]={0b1111011,//0
0b1001000,//1
0b0111101,//2
0b1101101,//3
0b1001110,//4
0b1100111,//5
0b1110111,//6
0b1001001,//7
0b1111111,//8
0b1101111//9
};
struct num{//数字
int val;//权值
int des;//描述
/*
_ 1
|_| 2 3 4
|_| 5 6 7
*/
/* 7 6 5 4 3 2 1
1 4 7 1 0 0 1 0 0 0
2 1 3 4 5 6 0 1 1 1 1 0 1
3 1 3 4 6 7 1 1 0 1 1 0 1
4 2 3 4 7 1 0 0 1 1 1 0
5 1 2 3 6 7 1 1 0 0 1 1 1
6 1 2 3 5 6 7 1 1 1 0 1 1 1
7 1 4 7 1 0 0 1 0 0 1
8 1 2 3 4 5 6 7 1 1 1 1 1 1 1
9 1 2 3 4 6 7 1 1 0 1 1 1 1
0 1 2 4 5 6 7 1 1 1 1 0 1 1
*/
bool check(){//检验是否合法
for(int i=0;i<10;i++)
if(val==n[i])
return true;
return false;
}
bool check(int w){//检验第w根是否存在
if(val>>w&1!=0)return true;
return false;
}
bool change(int w){//更改w根的位置
val^=(1<<w);
}
int get(){
for(int i=0;i<10;i++)
if(val==n[i])
return i;
}
num(int _N=0,int Wi=0,int type=0){//_N表示数值 Wi表示位置
val=n[_N];
des=type*pow(10,Wi);
}
}a[2000];
bool check(num *t,int L){//检查
int num=0;
for(int i=1;i<=L;i++){
if(!t[i].check())return false;
num+=t[i].des*t[i].get();
}
return num==0;
}
int tot=0;
signed main(){
//freopen("t.in","r",stdin);
int len=0,eq=1;
while(true){
ch[++len]=getchar();
if(ch[len]=='#')break;
}
while(ch[eq]!='=')eq++;
//分别处理等号前后
//把右边的等价到左边
for(int i=len-1,j;i>eq;i=j-1){
j=i;
while(j-1>0&&isdigit(ch[j-1]))j--;
int type=-1;
if(ch[j-1]=='-')type=1;
for(int w=i;w>=j;w--)
a[++tot]=num(ch[w]-'0',i-w,type);
if(ch[j-1]=='+'||ch[j-1]=='-')j--;
}
for(int i=eq-1,j;i>=1;i=j-1){
j=i;
while(j-1>0&&isdigit(ch[j-1]))j--;
int type=1;
if(ch[j-1]=='-')type=-1;
for(int w=i;w>=j;w--)
a[++tot]=num(ch[w]-'0',i-w,type);
if(ch[j-1]=='+'||ch[j-1]=='-')j--;
}
//for(int i=1;i<=tot;i++)
// printf("%d*%d ",a[i].get(),a[i].des);
check(a,tot);
for(int i=1;i<=tot;i++)
for(int j=0;j<8;j++)//枚举拿走的火柴
if(a[i].check(j))
for(int w=1;w<=tot;w++)
for(int k=0;k<8;k++)
if(!a[w].check(k)){
//将i的j放到w的k上
a[i].change(j);
a[w].change(k);
if(check(a,tot)){
int p=tot;
for(int i=1;i<=len;i++)
if(isdigit(ch[i]))putchar(a[p--].get()+'0');
else putchar(ch[i]);
return 0;
}
a[i].change(j);
a[w].change(k);
}
printf("No");
return 0;
}
跑得慢了点但能过就对了