• 292C Beautiful IP Addresses


    传送门

    题目

    The problem uses a simplified TCP/IP address model, please read the statement carefully.

    An IP address is a 32-bit integer, represented as a group of four decimal 8-bit integers (without leading zeroes), separated by commas. For example, record 0.255.1.123 shows a correct IP address and records 0.256.1.123 and 0.255.1.01 do not. In the given problem an arbitrary group of four 8-bit integers is a correct IP address.

    Our hero Polycarpus still works as a system administrator in some large corporation. He likes beautiful IP addresses. To check if some IP address is beautiful, he should do the following:

    1. write out in a line four 8-bit numbers of the IP address, without the commas;
    2. check if the resulting string is a palindrome.

    Let us remind you that a palindrome is a string that reads the same from right to left and from left to right.

    For example, IP addresses 12.102.20.121 and 0.3.14.130 are beautiful (as strings "1210220121" and "0314130" are palindromes), and IP addresses 1.20.20.1 and 100.4.4.1 are not.

    Polycarpus wants to find all beautiful IP addresses that have the given set of digits. Each digit from the set must occur in the IP address at least once. IP address must not contain any other digits. Help him to cope with this difficult task.

    Input

    The first line contains a single integer n (1 ≤ n ≤ 10) — the number of digits in the set. The second line contains the set of integers a1, a2, ..., an (0 ≤ ai ≤ 9). It is guaranteed that all digits in the set are distinct.
    Output
    In the first line print a single integer k — the number of beautiful IP addresses that contain the given set of digits. In the following k lines print the IP addresses, one per line in the arbitrary order.
    Examples
    Input
      6
    0 1 2 9 8 7
    Output
    6

    78.190.209.187
    79.180.208.197
    87.190.209.178
    89.170.207.198
    97.180.208.179
    98.170.207.18
    Input
    1

    4
    Output
    16

    4.4.4.4
    4.4.4.44
    4.4.44.4
    4.4.44.44
    4.44.4.4
    4.44.4.44
    4.44.44.4
    4.44.44.44
    44.4.4.4
    44.4.4.44
    44.4.44.4
    44.4.44.44
    44.44.4.4
    44.44.4.44
    44.44.44.4
    44.44.44.44
    题目大意
    给你n个数,问由这n个数组成的回文合法ip地址的数量并输出它们。

    分析

    首先,我们不难想出最朴素的暴力,枚举所有长度并构造,然后进行判断。不过,这显然是不行的。然后我们在考虑减少构造的长度,首先,因为我们要构造回文串,所以我们可以只枚举长度的一半的上取整,这样即避免了判断回文的时间,又减少了构造所需时间。确定大致思路后我们还有一些要考虑的细节:

            一、确定构造长度:开始我先到可能有两种情况(123321型和12321型),但之后我又想到还可能有一种情况(1231321型),但在wa12之后(面向数据编程QAQ),我发现对于任何长度大于等于2*n的长度都可以构造,并可以将它们分成模2余0和模2余1两种情况。

           二、构造:开始在想到三种构造长度情况后我想到了枚举n个数的不同顺序,但在wa5之后我发现了n<len/2这种情况继而想到12322321型,但进一步考虑后我发现12233221型,所有在构造是我们不考虑一个数是否出现过而考虑在构造完成后是否n个数全部用上了。

          三、分隔并判断:只需考虑将每一节分成1个数、2个数、3个数三种情况,然后再判断是否将整个数列全部分完并分成4节即可。

    代码

    #include<iostream>

    #include<cstdio>

    #include<cstring>

    #include<string>

    #include<algorithm>

    #include<cctype>

    #include<cmath>

    #include<cstdlib>

    #include<queue>

    #include<ctime>

    #include<vector>

    #include<set>

    #include<map>

    #include<stack>

    using namespace std;

    int a[20],ans[20],used[20],pr[4];

    int s[4][100000];

    int cnt;

    inline void check(int len,int i,int j){

      if(i==len+1&&j==4){

       s[0][++cnt]=pr[0];

       s[1][cnt]=pr[1];

       s[2][cnt]=pr[2];

       s[3][cnt]=pr[3];

       return;

      }

      if(i==len+1&&j<4)return;

      if(j==4&&i<len+1)return;

      if(i<=len){

       pr[j]=ans[i];

       check(len,i+1,j+1);

      }

      if(i+1<=len&&ans[i]!=0){

       pr[j]=ans[i]*10+ans[i+1];

       check(len,i+2,j+1);

      }

      if(i+2<=len&&ans[i]!=0&&ans[i]*100+ans[i+1]*10+ans[i+2]<256){

       pr[j]=ans[i]*100+ans[i+1]*10+ans[i+2];

       check(len,i+3,j+1);

      }

    }

    inline void make(int pl,int n,int len,int sum){

      if(n-sum>len/2+1-pl)return;

      if(pl==len/2+1&&sum==n){

        for(int i=len/2+1;i<=len;i++)

           ans[i]=ans[len-i+1];

        check(len,1,0);

        return;

      }

      for(int i=1;i<=n;i++){

           int k=0;

          if(!used[i])used[i]=1,sum++,k=1;

          ans[pl]=a[i];

          make(pl+1,n,len,sum);

          if(k)used[i]=0,sum--;

         }

      return;

    }

    inline void go(int len,int n){

      make(1,n,len,0);

      return;   

    }

    inline void make2(int pl,int n,int len,int sum){

      if(n-sum>(len+1)/2+1-pl)return;

      if(pl==(len+1)/2+1&&sum==n){

        for(int i=(len+1)/2+1;i<=len;i++)

           ans[i]=ans[(len+1)-i];

        check(len,1,0);

        return;

      }

      for(int i=1;i<=n;i++){

           int k=0;

          if(!used[i])used[i]=1,sum++,k=1;

          ans[pl]=a[i];

          make2(pl+1,n,len,sum);

          if(k)used[i]=0,sum--;

         }

      return;

    }

    inline void go2(int len,int n){

      make2(1,n,len,0);

      return;   

    }

    int main()

    {     int n,m,i,j,k;

          cin>>n;

          for(i=1;i<=n;i++)

             cin>>a[i];

          if(n>=7){

           puts("0");

           return 0;

          }

          for(i=4;i<=12;i++)

             if(i>=2*n&&i%2==0){

              go(i,n);

             }else if(i>=2*n-1&&i%2==1){

              go2(i,n);

             }

          cout<<cnt<<endl;

          for(i=1;i<=cnt;i++)

             printf("%d.%d.%d.%d ",s[0][i],s[1][i],s[2][i],s[3][i]);

      return 0;

    }

     

  • 相关阅读:
    转场动画3-手势返回
    UITableViewCell的选中时的颜色设置
    git的使用
    MarkDown语法学习笔记
    移动作业
    移动开发音乐播放器
    python循环删除list中的元素
    Linux权限管理
    Linux用户和用户组
    数据库常用基础操作
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/8873798.html
Copyright © 2020-2023  润新知