P2456 [SDOI2006]二进制方程

P2456 [SDOI2006]二进制方程

题解

拿个样例模拟一下发现

把等式两边对应展开,每个位置的填数都是一一对应的

比如第二个样例

分类讨论:

(1)xi  yi  都是数字,但是不相同,此时无解

(2)xi  yi  都是数字,相同,唯一填法

(3)xi  yi  一个是数字,一个是字母,唯一填法

(4)xi  yi  都是字母,颜色不同,那么一旦在该颜色对应的位置上填了一个数字,对应的另一种颜色,或者是该颜色在其他区域的对应位置也填上了这个数字

       所以我们就把同一种颜色的方块用并查集联系起来

 

解释代码:

(1)num[ ] 给0,1,每一个字母每一个位置都有唯一的编号,num[ i ]记录第 i 种字母的最后一个位置在哪里,但是实际应用起来就是下表对应的亚子:

 

 

这么做是方便以后的并查集

 (2)sum记录多少个待确定的位置(也就是有两种填法),答案其实是 2待确定位置数

 (3)x[ ] y[ ] 记录展开后的式子

 (4)判断无解,1是x[  ] y[  ]长度不一样,2是 xi  yi 的祖先一个是1 一个是0

 (5)取最大的一个的父亲是最小的一个

 (6)高精度

 

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdlib>
#include<queue>

using namespace std;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int num[28],x[10010],y[10010],fa[100010],sum=0,t1=0,t2=0,k;
char s[10010];
int c[1000010],lenc;

int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

void cheng()
{
    c[0]*=2;
    for(int i=1;i<lenc;i++)
    {
        c[i]=c[i]*2+c[i-1]/10;
        c[i-1]%=10;
    }
    while(c[lenc-1]>=10)
    {
        c[lenc]=c[lenc-1]/10;
        c[lenc-1]%=10;
        lenc++;
    }
}

int main()
{
    k=read();
    num[1]=2;  //解释1 
    for(int i=2,u;i<=k+1;i++)
    {
        u=read();
        num[i]=num[i-1]+u;
        sum+=u;  //解释2 
    }
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        if(s[i]>='a'&&s[i]<='z')
        {
            int v=s[i]-'a'+1;
            for(int j=num[v];j<num[v+1];j++) x[++t1]=j;
        } 
        else x[++t1]=s[i]-'0';
    }
    scanf("%s",s);
    len=strlen(s);
    for(int i=0;i<len;i++)
    {
        if(s[i]>='a'&&s[i]<='z')
        {
            int v=s[i]-'a'+1;
            for(int j=num[v];j<num[v+1];j++) y[++t2]=j;
        } 
        else y[++t2]=s[i]-'0';
    }
    
    if(t1!=t2){ printf("0\n");return 0; }  //无解判断 
    
    for(int i=0;i<=num[k+1];i++) fa[i]=i;
    
    for(int i=1;i<=t1;i++)
    {
        int f1=find(x[i]),f2=find(y[i]);
        if(f1+f2==1) { printf("0\n");return 0; } //解释4 
        if(f1!=f2)
        {
            fa[max(f1,f2)]=min(f1,f2);  //解释5 
            sum--; //少了一个可以填两种方案的 
        }
    }
    
    c[0]=1;lenc=1;
    for(int i=sum;i>=1;i--)
      cheng();  //解释6 
    for(int i=lenc-1;i>=0;i--)
      printf("%d",c[i]);
    
    return 0;
}

 

posted @ 2019-08-20 21:30  晔子  阅读(332)  评论(0编辑  收藏  举报