UVALive - 4845 组合数

Password
Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu

Submit Status

Description

Shoulder-surfing is the behavior of intentionally and stealthily watching the screen of another person's electronic device, such as laptop computer or mobile phone. Since mobile devices prevail, it is getting serious to steal personal information by shoulder-surfing.

Suppose that we have a smart phone. If we touch the screen keyboard directly to enter the password, this is very vulnerable since a shoulder-surfer easily knows what we have typed. So it is desirable to conceal the input information to discourage shoulder-surfers around us. Let me explain one way to do this.

You are given a 6 x 5 grid. Each column can be considered the visible part of a wheel. So you can easily rotate each column wheel independently to make password characters visible. In this problem, we assume that each wheel contains the 26 upper letters of English alphabet. See the following Figure 1.

Figure 1.  6 x 5 window clips a valid grid representation for a password.

Assume that we have a length-5 password such as p1 p2 p3 p4 p5. In order to pass the authentication procedure, we should construct a configuration of grid space where each pi appears in the i-th column of the grid. In that situation we say that the user password is accepted.

Let me start with one example. Suppose that our password was set `COMPU'. If we construct the grid as shown in Figure 2 on next page, then the authentication is successfully processed.

Figure 2. A valid grid representation for password `COMPU'.

In this password system, the position of each password character in each column is meaningless. If each of the 5 characters inp1 p2 p3 p4 p5 appears in the corresponding column, that can be considered the correct password. So there are many grid configurations allowing one password. Note that the sequence of letters on each wheel is randomly determined for each trial and for each column. In practice, the user is able to rotate each column and press ``Enter" key, so a should-surfer cannot perceive the password by observing the 6 x 5 grid since there are too many password candidates. In this 6 x 5 grid space, maximally 65 = 7, 776cases are possible. This is the basic idea of the proposed password system against shoulder-surfers.

Unfortunately there is a problem. If a shoulder-surfer can observe more than two grid plate configurations for a person, then the shoulder-surfer can reduce the searching space and guess the correct password. Even though it is not easy to stealthily observe other's more than once, this is one weakness of implicit grid passwords.

Let me show one example with two observed configurations for a grid password. The user password is `COMPU', but `DPMAG' is also one candidate password derived from the following configuration.

Figure 3. Both of `COMPU' and `DPMAG' are feasible password .

You are given two configurations of grid password from a shoulder-surfer. Suppose that you have succeeded to stealthily record snapshots of the target person's device (e.g. smart phone). Then your next task is to reconstruct all possible passwords from these two snapshots. Since there are lots of password candidates, you are asked for the k-th password among all candidates in lexicographical order. In Figure 3, let us show the first 5 valid password. The first 5 valid passwords are `ABGAG' , `ABGAS', `ABGAU', `ABGPG' and `ABGPS'.

The number k is given in each test case differently. If there does not exist a k-th password since k is larger than the number of all possible passwords, then you should print `NO' in the output.

Input

Your program is to read from standard input. The input consists of T test cases. The number of test cases T is given in the first line of the input. The first line of each test case contains one integer, K, the order of the password you should find. Note that 1K7, 777. Next the following 6 lines show the 6 rows of the first grid and another 6 lines represent the 6 rows of the second grid.

Output

Your program is to write to standard output. Print exactly the  k-th password (including `  NO') in one line for each test case.

The following shows sample input and output for three test cases.

Sample Input

3
1
AYGSU
DOMRA
CPFAS
XBODG
WDYPK
PRXWO
CBOPT
DOSBG
GTRAR
APMMS
WSXNU
EFGHI
5
AYGSU
DOMRA
CPFAS
XBODG
WDYPK
PRXWO
CBOPT
DOSBG
GTRAR
APMMS
WSXNU
EFGHI
64
FGHIJ
EFGHI
DEFGH
CDEFG
BCDEF
ABCDE
WBXDY
UWYXZ
XXZFG
YYFYH
EZWZI
ZGHIJ

Sample Output

ABGAG
ABGPS
NO



//递推法
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

char G[2][6][5],ans[6];//G存表,ans存结果
char Select[5][6];//按字母序存每一列可能出现的字母
int cnt[5],he[5];//cnt存每一列满足的字母的数量,he存后缀可能出现的情况数
char vis[2][26];//存每一列的是否出现的字母,vis[i][j]==1表示第j个字母出现过

int main()
{
    int T,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&k);
        for(int i = 0;i < 2;i++)
        {
            for(int j = 0;j < 6;j++)
            {
                scanf("%s",G[i][j]);
            }
        }

        //先算出后缀积,和每一列可能出现的字母的二维表
        memset(cnt,0,sizeof(cnt));
        for(int i = 0;i < 5;i++)//i表示列数
        {
            memset(vis,false,sizeof(vis));
            for(int j = 0;j < 2;j++)//两张表
            {
                for(int m = 0;m < 6;m++)//行
                    vis[j][G[j][m][i] - 'A'] = 1;
            }
            //按字母序遍历
            for(int j = 0;j < 26;j++)
            {
                if(vis[0][j] && vis[1][j])
                    Select[i][++cnt[i]] = j + 'A';
            }
        }
        //长度为5的后缀没有,所以
        he[5] = 1;
        for(int i = 4;i >= 0;i--)
        {
            he[i] = he[i + 1] * cnt[i];
        }
        if(k > he[0])
        {
            printf("NO\n");
            continue;
        }
        k--;//程序中从0开始计算
        for(int i = 0;i < 5;i++)
        {
            int t = k / he[i + 1];  //判断第i个字母选第几个
            ans[i] = Select[i][t + 1];
            k %= he[i+1];
        }
        ans[5] = '\0';
        printf("%s\n",ans);
    }
    return 0;
}



//暴力搜索
#include <iostream>
#include <cstdio>
#include <cstring>

int k,cnt;
char G[2][6][5],ans[6];//G数组用来存两张表,ans用来存结果

using namespace std;

bool dfs(int col)
{
    //col==5表示找到一组字典序的序列
    if(col == 5)
    {
        if(++cnt == k)
        {
            ans[col] = '\0';//输出结束的标志
            printf("%s\n",ans);
            return true;
        }
        return false;
    }

    bool vis[2][26];
    memset(vis,false,sizeof(vis));
    for(int i = 0;i < 2;i++)
    {
        for(int j = 0;j < 6;j++)
            vis[i][G[i][j][col] - 'A'] = 1;
    }
    //按字典序的
    for(int i = 0;i < 26;i++)
    {
        if(vis[0][i] && vis[1][i])
        {
            ans[col] = i + 'A';
            if(dfs(col + 1))//说明在dfs(col + 1)时找到结果了
                return true;
        }
    }
    return false;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&k);
        for(int i = 0;i < 2;i++)
        {
            for(int j = 0;j < 6;j++)
            {
                scanf("%s",G[i][j]);
            }
        }
        cnt = 0;
        if(!dfs(0))
            printf("NO\n");
    }
    return 0;
}



你可能感兴趣的:(UVALive - 4845 组合数)