[NOI2000]算符破译
NOI2000的题吓死人啊。
一开始写了一个裸的搜索,发现样例跑的都有点吃力。然后弃疗了。
看完题解后觉得其实优化也不是很难想。
显然先枚举=+*。然后每一行之前没出现过的字符就暴力枚举对应的数字。
这样做不加剪枝是过不了的。
然后有一个显然的优化是,=+*这三个确定后一块块数字的位数也就确定了。
对于每一行,我们算出左右两边的可能的答案位数范围,然后判断有无交集,没有就不合法。
然后就能过了?
当然,还有一些,比如说当前搜下去不会对答案产生变动就剪枝。
其实还可以加上如从低位到高位搜,然后确定低位,不合法就剪枝。但感觉这个有点烦就没加。
#include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<vector> #include<map> #include<queue> #include<string> #include<bitset> #include<iomanip> #include<iostream> #include<cmath> using namespace std; #define rep(i,x,y) for(i=x;i<=y;i++) #define _rep(i,x,y) for(i=x;i>=y;i--) #define REP(i,x,y) for(int i=(x);i<=(y);i++) #define _REP(i,x,y) for(int i=(x);i>=(y);i--) #define CL(S,x) memset(S,x,sizeof(S)) #define CP(S1,S2) memcpy(S1,S2,sizeof(S2)) #define ALL(x,S) for(__typeof((v).end()) x=S.begin();x!=S.end();x++) #define pb push_back #define IN insert #define ER erase #define BE begin() #define ED end() #define LB lower_bound #define UB upper_bound #define mp make_pair #define fi first #define se second #define upmin(x,y) x=min(x,y) #define upmax(x,y) x=max(x,y) #define COUT(S,x) cout<<fixed<<setprecision(x)<<S<<endl template<class T> inline void read(T&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;}; template<class T> inline void read(T&x,T&y){read(x);read(y);} template<class T> inline void read(T&x,T&y,T&z){read(x);read(y);read(z);} inline char getc(){char c;for(c=getchar();c<=32;c=getchar());return c;} typedef long long ll; typedef long double ld; typedef pair<int,int> pii; const int inf=int(1e9); int T,n,i,j,k,l,p,c; char a[1111][13];int len[1111]; int w[15];int cnt[13][1111]; bool c2[15],c1[15];int lg2[(1<<10)+10]; int ans[15]; int st[15];bool mark[15]; bool near[128][128]; char eq,mul,add;bool sol; bool caneq() { CL(c1,1); for(char c='a';c<='m';c++) rep(i,1,T) { bool can2=1; rep(j,1,len[i]) { if(j<len[i])near[a[i][j]][a[i][j+1]]=near[a[i][j+1]][a[i][j]]=1; if(a[i][j]==c)cnt[c-'a'][i]++; } if(cnt[c-'a'][i]!=1)can2=0; if(a[i][1]==c||a[i][len[i]]==c){c1[c-'a']=0;can2=0;} c2[c-'a']=can2; } } bool D(int x){return x>=0;} int cl() { int i,tot=0; for(;mark[st[0]-1];st[0]--) st[st[0]-1]=st[st[0]-1]*st[st[0]]; rep(i,1,st[0])tot+=st[i];st[0]=0; return tot; } bool check(int d) { int i,j,k,la=-1,left=-1,right=-1;st[0]=0; rep(i,1,len[d]) { int c=w[a[d][i]-'a']; if(D(c)) if(D(la))st[st[0]]=st[st[0]]*10+c; else st[++st[0]]=c; else { if(st[0]==0)return 0; for(;mark[st[0]-1];st[0]--) st[st[0]-1]=st[st[0]-1]*st[st[0]]; if(c==-3)mark[st[0]]=1; else if(c==-1)left=cl(); else mark[st[0]]=0; } la=c; } right=cl(); return left==right; } void go(int d,int nl,int S) //dfs { bool ppp=1;rep(i,0,12)if(!(ans[i]==w[i]||ans[i]==-200)){ppp=0;break;}if(ppp)return; if(d>T) { //rep(i,0,12) printf("%c : %d\n",'a'+i,w[i]);printf("end\n"); sol=1; rep(i,0,12)if(w[i]!=inf) { if(ans[i]==-100)ans[i]=w[i]; else if(ans[i]!=w[i])ans[i]=-200; } else ans[i]=-200; return; } else { if(nl>len[d]) { if(check(d)) go(d+1,1,S); return; } int cc=a[d][nl]-'a'; if(w[cc]==inf) { for(int S2=S;S2;S2-=S2&-S2) { int t=lg2[S2&-S2]; if(nl==1&&t==0&&w[a[d][2]-'a']>0)continue; w[cc]=t; go(d,nl+1,S-(S2&-S2)); w[cc]=inf; } } else go(d,nl+1,S); } } void print() { int i; rep(i,0,12) if(ans[i]>=-3) { putchar('a'+i); if(ans[i]==-3)putchar('*'); else if(ans[i]==-2)putchar('+'); else if(ans[i]==-1)putchar('='); else putchar('0'+ans[i]); putchar('\n'); } if(!sol)printf("noway\n"); } int g,lw[15],rw[15]; void clw(int&L,int&R){L=R=0;for(;g;g--)upmax(L,lw[g]),R=max(rw[g],R)+(R>0);} bool predfs() { int d,i,j,la,Llw,Lrw,Rlw,Rrw; rep(d,1,T){ g=0;la=-1; rep(i,1,len[d]){ int c=w[a[d][i]-'a']; if(c==inf){if(la<0)g++,lw[g]=rw[g]=0;lw[g]++;rw[g]++;} else{ if(g==0)return 0; for(;mark[g-1];g--) lw[g-1]+=lw[g]-1,rw[g-1]+=rw[g]; if(c==-3)mark[g]=1; else if(c==-2)mark[g]=0; else if(c==-1)clw(Llw,Lrw); } la=c; } clw(Rlw,Rrw); if(Lrw<Rlw||Rrw<Llw) { return 0; } } return 1; } int main() { //freopen("eqution.in","r",stdin);freopen("eqution.out","w",stdout); read(T);rep(i,1,T)scanf("%s",a[i]+1),len[i]=strlen(a[i]+1); rep(i,0,10)lg2[1<<i]=i; caneq(); rep(i,0,12)ans[i]=-100; for(eq='a';eq<='m';eq++)if(c2[eq-'a']) for(mul='a';mul<='m';mul++)if(c1[mul-'a']) for(add='a';add<='m';add++)if(c1[add-'a']) if(eq!=mul&&add!=mul&&eq!=add) if(!near[eq][mul]&&!near[eq][add]&&!near[mul][add]) { rep(i,0,12)w[i]=inf;w[eq-'a']=-1;w[add-'a']=-2;w[mul-'a']=-3; if(!predfs())continue; go(1,1,(1<<10)-1); } print(); return 0; }