zoukankan      html  css  js  c++  java
  • NOIP2004 虫食算

    https://www.luogu.org/problem/show?pid=1092

    题目描述

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

    43#9865#045

    +8468#6633

    44445509678

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

    现在,我们对问题做两个限制:

    首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。

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

    BADC

    • CBDA

    DCCC 上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解

    输入输出格式

    输入格式:

    包含四行。第一行有一个正整数N(N<=26),后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。

    输出格式:

    包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

    输入输出样例

    输入样例#1:
    5
    ABCED
    BDACE
    EBBAA
    
    输出样例#1:
    1 0 3 4 2
    

    说明

    对于30%的数据,保证有N<=10;

    对于50%的数据,保证有N<=15;

    对于全部的数据,保证有N<=26。

    最暴力的搜索:枚举每个字母代表什么,检验

    优化:

    O、对于当前列的三个字符是否已经确定分8种情况讨论

    (3个都确定,确定2个*3,只确定1个*3,都没确定)

    1、3个都确定的,直接判断

    2、确定了2个的,推出第3个

    3、只确定1个的,枚举一个,推出另一个

    4、都没确定的,枚举前两个,推第三个,这样可以不用枚举是否进位

    A、对于搜索顺序的优化:

    1、小学算竖式?从右往左算! 所以按竖式从右往左枚举,低位的进位对高位有影响

    2、枚举字母代表的数字从n-1往小枚举,因为最高位不会进位,高位比较小(优化的关键)

    B、一般都能想到的优化:

    1、用一个数组,记录这个数字是否已经被用过(代码中的use[])

    2、一旦结果搜出来了,设标志变量,一路return之至主函数,最好在每个递归回溯前都写一个。(exit(0)也可以,但不确定NOIP可不可以用)

    C、进位的优化:

    1、用一个数组记录当前位是否进位,代码中的bit[]

    2、如果这一列的左边一列3个数都齐了,判断在满足他们的情况下,这一列是否需要进位

    D、剪枝的关键:

    枚举这一列左边的列,如果他们3个数都齐了,判断在进位/不进位的情况下是否成立,不成立则return

    没有这个剪枝过不了第9个点

     注意(我犯的错误):

    1、并不是同一列中的三个字母代表数字都不能相同,需要判断一下有没有重复字母

    这种情况只会影响确定1个 和 都没确定得到情况

    对于只确定1个字母的列,只需要判断枚举出的数是否出现过即可

    对于3个字母都没确定的列,在枚举前两个的时候要判断前两个字母是否相等

    2、低位往高位进1,高位算的时候不是想当然的10啊,是n,这是n进制

    #include<cstdio>
    #include<cstring>
    #include<algorithm> 
    using namespace std;
    int n;
    char a[30],b[30],c[30];
    int ans[30];
    bool ok,use[30],bit[30];
    inline void dfs(int now)
    {
        if(ok) return;
        if(now<0)
        {
            for(int i=0;i<n;i++) printf("%d ",ans[i]);
            ok=true;
            return;
        }
        int flag=2;
        if(now && ans[a[now-1]-'A']!=-1 && ans[b[now-1]-'A']!=-1 && ans[c[now-1]-'A']!=-1) 
        {
            if((ans[a[now-1]-'A']+ans[b[now-1]-'A'])%n==ans[c[now-1]-'A']) flag=0;
            else if((ans[a[now-1]-'A']+ans[b[now-1]-'A']+1)%n==ans[c[now-1]-'A']) flag=1;
            else return;    
        }
        for(int i=now-2;i>=0;i--)
        {
            if(ans[a[i]-'A']!=-1 && ans[b[i]-'A']!=-1 && ans[c[i]-'A']!=-1)
             if((ans[a[i]-'A']+ans[b[i]-'A'])%n!=ans[c[i]-'A'] && (ans[a[i]-'A']+ans[b[i]-'A']+1)%n!=ans[c[i]-'A']) 
              return;
        }
        int & aa=ans[a[now]-'A'],& bb=ans[b[now]-'A'],& cc=ans[c[now]-'A'];
        if(aa!=-1 && bb!=-1  && cc!=-1)
        {
            if((aa+bb+bit[now])%n==cc) 
            {
                bit[now-1]=(aa+bb+bit[now])/n;
                if(flag!=2 && bit[now-1]!=flag) return;
                dfs(now-1);
                if(ok) return;
            }
            else return; 
        }
        else if(aa!=-1 && bb!=-1)
        {
            if(use[(aa+bb+bit[now])%n]) return;
            bit[now-1]=(aa+bb+bit[now])/n;
            if(flag!=2 && bit[now-1]!=flag) return;
            cc=(aa+bb+bit[now])%n;
            use[cc]=true;
            dfs(now-1);
            if(ok) return;
            use[cc]=false;
            cc=-1;
        }
        else if(aa!=-1 && cc!=-1)
        {
            if(aa+bit[now]<=cc)
            {
                if(use[cc-aa-bit[now]]) return;
                bit[now-1]=0;
                if(flag!=2 && bit[now-1]!=flag) return;
                bb=cc-aa-bit[now];
                use[bb]=true;
                dfs(now-1);
                if(ok) return;
            }
            else
            {
                if(use[cc+n-aa-bit[now]]) return;
                bit[now-1]=true;
                if(flag!=2 && bit[now-1]!=flag) return;
                bb=(cc+n-aa-bit[now])%n;
                use[bb]=true;
                dfs(now-1);
                if(ok) return; 
            }
            use[bb]=false;
            bb=-1;
        }
        else if(bb!=-1 && cc!=-1)
        {
            if(bb+bit[now]<=cc)
            {
                if(use[cc-bb-bit[now]]) return; 
                bit[now-1]=0;
                if(flag!=2 && bit[now-1]!=flag) return;
                aa=cc-bb-bit[now];
                use[aa]=true;
                dfs(now-1);
                if(ok) return;
            }
            else
            {
                if(use[cc+n-bb-bit[now]]) return;
                bit[now-1]=true;
                if(flag!=2 && bit[now-1]!=flag) return;
                aa=(cc+n-bb-bit[now])%n;
                use[aa]=true;
                dfs(now-1);
                if(ok) return;
            }
            use[aa]=false;
            aa=-1;
        }
        else if(aa!=-1)
        {
            for(int i=n-1;i>=0;i--)
            {
                if(use[i]) continue;
                if(use[(aa+i+bit[now])%n]) continue;
                bit[now-1]=(aa+i+bit[now])/n;
                if(flag!=2 && bit[now-1]!=flag) return;
                bb=i; cc=(aa+i+bit[now])%n;
                use[bb]=use[cc]=true;
                dfs(now-1);
                if(ok) return;
                use[bb]=use[cc]=false;
                bb=cc=-1;
            }
        }
        else if(bb!=-1)
        {
            for(int i=n-1;i>=0;i--)
            {
                if(use[i]) continue;
                if(use[(bb+i+bit[now])%n]) continue;
                bit[now-1]=(i+bb+bit[now])/n;
                if(flag!=2 && bit[now-1]!=flag) return;
                aa=i; cc=(bb+i+bit[now])%n;
                use[aa]=use[cc]=true;
                dfs(now-1);
                if(ok) return;
                use[aa]=use[cc]=false;
                aa=cc=-1;
            }
        }
        else if(cc!=-1)
        {
            for(int i=n-1;i>=0;i--)
            {
                if(use[i]) continue;
                if(i+bit[now]<=cc && !use[cc-i-bit[now]])
                {
                    bit[now-1]=0;
                    if(flag!=2 && bit[now-1]!=flag) return;
                    aa=i; bb=cc-i-bit[now];
                    use[aa]=use[bb]=true;
                    dfs(now-1);
                    if(ok) return;
                    use[aa]=use[bb]=false;
                    aa=bb=-1;
                }
                else if(i+bit[now]>cc && !use[cc+n-i-bit[now]])
                {     
                    bit[now-1]=1;
                    if(flag!=2 && bit[now-1]!=flag) return;
                    aa=i; bb=(cc+n-i-bit[now])%n;
                    use[aa]=use[bb]=true;
                    dfs(now-1);
                    if(ok) return;
                    use[aa]=use[bb]=false;
                    aa=bb=-1;
                }
            }
        }
        else
        {
            for(int i=n-1;i>=0;i--)
            {
                if(use[i]) continue;
                for(int j=n-1;j>=0;j--)
                {
                    if((a[now]!=b[now] && i==j) || (a[now]==b[now] && i!=j) || use[j] || use[(i+j+bit[now])%n]) continue;
                    bit[now-1]=(i+j+bit[now])/n;
                    if(flag!=2 && bit[now-1]!=flag) return;
                    aa=i; bb=j; cc=(i+j+bit[now])%n;
                    use[aa]=use[bb]=use[cc]=true;
                    dfs(now-1);
                    if(ok) return;
                    use[aa]=use[bb]=use[cc]=false;
                    aa=bb=cc=-1; 
                }
            }
        }
    }
    int main()
    {
        scanf("%d%s%s%s",&n,a,b,c);
        memset(ans,-1,sizeof(ans));
        dfs(n-1);
    }

  • 相关阅读:
    转移到新的个人独立博客。
    hdu5618 (三维偏序,cdq分治)
    平衡树维护动态凸包
    poj1986 LCA
    hdu2586 LCA
    LCA最近公共祖先 ST+RMQ在线算法
    hdu 3401 单调队列优化DP
    【转】单调队列优化DP
    CodeForces 548D 单调栈
    hdu3530 单调队列
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7274630.html
Copyright © 2011-2022 走看看