読者です 読者をやめる 読者になる 読者になる

AOJ 2604: Pattern Language

文字ごとに桁数と(2桁なら)一の位が制約つきかを決めて(3^n通りある)
場合わけをひたすらがんばって数えるだけ。
まあ、解いてる人数が少ないだけあってつまらなかった。

#include<stdio.h>
#include<algorithm>
using namespace std;
char str[1100];
char in[2];
int u[110];
int mod=1000000007;
int UF[110];
int FIND(int a){
	if(UF[a]<0)return a;
	return UF[a]=FIND(UF[a]);
}
void UNION(int a,int b){
	a=FIND(a);b=FIND(b);if(a==b)return;
	UF[a]+=UF[b];UF[b]=a;
}
char tmp[1100];
int L[110];
int R[110];
int ml[110];
int mr[110];
int pow3[13];
int main(){
	pow3[0]=1;
	for(int i=1;i<13;i++)pow3[i]=pow3[i-1]*3;
	int a,b;
	scanf("%d%d",&a,&b);
	scanf("%s",str);
	for(int i=0;i<b;i++){
		int c;
		scanf("%s%d",in,&c);
		u[in[0]-'a']=c;
	}
	int ret=0;
	for(int i=0;i<pow3[10];i++){
		bool dame=false;
		for(int j=0;j<110;j++)UF[j]=L[j]=R[j]=-1;
		for(int j=0;j<10;j++)ml[j]=mr[j]=0;
		for(int j=0;j<10;j++){
			if(u[j]<10&&(i%pow3[j+1]/pow3[j]))dame=true;
			if(i%pow3[j+1]/pow3[j]==2){
				L[j]=u[j]/10;
				
			}
			if(u[j]<10||i%pow3[j+1]/pow3[j]==2){
				ml[j]=u[j]/10;
				mr[j]=u[j]%10;
			}else{
				if(i%pow3[j+1]/pow3[j])ml[j]=u[j]/10-1;
				else ml[j]=0;
				mr[j]=9;
			}
	//		if(u[j]<20&&(i%pow3[j+1]/pow3[j]==1))dame=true;
		}
		if(dame)continue;
		int sz=0;
		for(int j=0;j<a;j++){
			if('0'<=str[j]&&str[j]<='9')tmp[sz++]=str[j];
			else{
				int p=str[j]-'a';
				if(i%pow3[p+1]/pow3[p]){
					tmp[sz++]='A'+p;
					tmp[sz++]=str[j];
				}else tmp[sz++]=str[j];
			}
		}
		for(int j=0;j<sz;j++){
			if('0'<=tmp[j]&&tmp[j]<='9'){
				if('0'<=tmp[sz-1-j]&&tmp[sz-1-j]<='9'){
					if(tmp[j]!=tmp[sz-1-j])dame=true;
				}else if('A'<=tmp[sz-1-j]&&tmp[sz-1-j]<='Z'){
					if(~L[tmp[sz-1-j]-'A']&&L[tmp[sz-1-j]-'A']!=tmp[j]-'0')dame=true;
					L[tmp[sz-1-j]-'A']=tmp[j]-'0';
				}else{
					if(~R[tmp[sz-1-j]-'a']&&R[tmp[sz-1-j]-'a']!=tmp[j]-'0')dame=true;
					R[tmp[sz-1-j]-'a']=tmp[j]-'0';
				}
			}else if('A'<=tmp[j]&&tmp[j]<='Z'){
				if('A'<=tmp[sz-1-j]&&tmp[sz-1-j]<='Z'){
					UNION(tmp[j]-'A',tmp[sz-1-j]-'A');
				}
				if('a'<=tmp[sz-1-j]&&tmp[sz-1-j]<='z'){
					UNION(tmp[j]-'A',10+tmp[sz-1-j]-'a');
				}
			}else{
				if('a'<=tmp[sz-1-j]&&tmp[sz-1-j]<='z'){
					UNION(tmp[j]-'a'+10,tmp[sz-1-j]-'a'+10);
				}
			}
		}
		for(int j=0;j<10;j++){
			for(int k=0;k<10;k++){
				if(~L[j]&&~L[k]&&FIND(j)==FIND(k)&&L[j]!=L[k])dame=true;
				if(~L[j]&&~R[k]&&FIND(j)==FIND(k+10)&&L[j]!=R[k])dame=true;
				if(~R[j]&&~R[k]&&FIND(j+10)==FIND(k+10)&&R[j]!=R[k])dame=true;
				if(R[k]==0&&FIND(j)==FIND(k+10))dame=true;
				if(L[k]==0)dame=true;
				if(FIND(j)==FIND(k)&&ml[j]<L[k])dame=true;
				if(FIND(j)==FIND(k+10)&&ml[j]<R[k])dame=true;
				if(FIND(j+10)==FIND(k)&&mr[j]<L[k])dame=true;
				if(FIND(j+10)==FIND(k+10)&&mr[j]<R[k])dame=true;
			}
		}
		if(dame)continue;
		long long val=1;
		for(int j=0;j<10;j++){
			if(UF[j+10]<0){
				if(!~R[j]){
					int mv=9;
					int nz=0;
					int one=0;
					for(int k=0;k<10;k++){
						if(FIND(j+10)==FIND(k)){
							if(~L[k])one=1;
							mv=min(mv,ml[k]);
							nz=1;
						}
						if(FIND(j+10)==FIND(k+10)){
							if(~R[k])one=1;
							mv=min(mv,mr[k]);
						}
					}
					//if(one)continue;
					if(one);
					else if(nz)val=val*mv%mod;
					else val=val*(mv+1)%mod;
				}
			}
			if(i%pow3[j+1]/pow3[j]){
				if(UF[j]<0){
					if(!~L[j]){	
						int mv=9;
						int	nz=1;
						int one=0;
						for(int k=0;k<10;k++){
							if(FIND(j)==FIND(k)){
								if(~L[k])one=1;
								mv=min(mv,ml[k]);
								nz=1;
							}
							if(FIND(j)==FIND(k+10)){
								if(~R[k])one=1;
								mv=min(mv,mr[k]);
							}
						}
						if(one);
						else if(nz)val=val*mv%mod;
						else val=val*(mv+1)%mod;
					}
				}
			}
		}
	//	for(int j=0;j<10;j++)printf("%d",i%pow3[j+1]/pow3[j]);
	//	printf(": %lld\n",val);
		ret=(ret+val)%mod;
	}
	printf("%d\n",ret);
}