【UVA1262】Password

题意

给出两个6行5列的字母矩阵,一个密码满足:密码的第i个字母在两个字母矩阵的第i列均出现。

然后找出字典序为k的密码,如果不存在输出NO。k≤7777

分析

由于k的范围很小,首先可以考虑dfs

但是这个题其实是在考康托展开

先把每个位置能填的数全部预处理出来,比如样例中每一位可选的分别是{ACDW}、{BOP}、{GMOX}、{AP}、{GSU}

那就是4*3*4*2*3=288种

来模拟一下如何解码,比如k=197,注意标红的数字

3*4*2*3=72 4*2*3=24 2*3=3=3  1

197÷72=2……53 所以第一位选D

53÷24=2……5 所以第二位选P

6=0……5 所以第三位选G

3=1……2 所以第四位选P

1=2……0 所以第五位选U

就能得到DPGPU,而我们在程序中模拟这个过程。处理出每个后缀乘积,并用上述方式得到的商+1就是选的位数,再用余数继续算。

调了好久,此题有坑,同一列中一个字母可以重复出现,所以别用map!!!

代码

#include<bits/stdc++.h>  
using namespace std;  
int T,k;  
char x;  
vector<char> ok[7];  
int mul[7],vis[7][128];  
int main()  
{  
    scanf("%d",&T);  
    while(T--)  
    {  
        memset(vis,0,sizeof(vis));  
        for(int i=1;i<=5;i++)ok[i].clear();  
        cin>>k;  
        for(int i=1;i<=6;i++)  
            for(int j=1;j<=5;j++)  
               {  
                    cin>>x;  
                    vis[j][x]=1;  
               }   
        for(int i=1;i<=6;i++)  
            for(int j=1;j<=5;j++)  
             {  
                cin>>x;  
                 if(vis[j][x])  
                {  
                    ok[j].push_back(x);  
                    vis[j][x]=0;  
                }  
             }    
        for(int i=1;i<=5;i++) sort(ok[i].begin(),ok[i].end());  
        mul[5]=1;  
        for(int i=4;i>=0;i--) mul[i]=mul[i+1]*ok[i+1].size();  
        if(k>mul[0]) cout<<"NO"<<endl;  
        else  
        {     
            k--;  
            for(int i=1;i<=5;i++)  
            {  
                int s=k/mul[i];  
                cout<<ok[i][s];  
                k=k%mul[i];  
            }  
            cout<<endl;  
        }  
    }  
    return 0;  
}  
原文地址:https://www.cnblogs.com/NSD-email0820/p/9867363.html