2019 年百度之星·程序设计大赛 - 初赛二

 

传送门:

  [1]:HDU

  [2]:bestcoder

 

 

B.度度熊与排列(思维)

•题意

  有一个数组 p,p 中包含的数为 1~m 的全排列,一个含 m 个字符的串 s;

  在 s 上有一个操作,对于 s 中的第 i 个位置的字符,放到 p[ i ] 位置,构成一个新串 t;

  即 $s_{i}=t_{p_i}$;

  给你 2n 个串,每两个串为一组,前一个串表示原串 s,后一个串表示经过 p 映射后的新串 t;

  求是否存在某个 1~m 的全排列,使得这 n 组串都可以经过 p 由 s 变为 t;

  如果存在,输出字典序最小的那组,如果不存在,输出 -1;

•题解

  $S=\begin{bmatrix} s_1: & s_{11} & s_{12} & \cdots & s_{1m} \\ s_2: & s_{21} & s_{22} & \cdots & s_{2m} \\ s_3: & s_{31} & s_{32} & \cdots & s_{3m} \\ \vdots & \vdots & \vdots & \vdots \ \vdots & \vdots \\s_n: & s_{n1} & s_{n2} & \cdots & s_{nm} \end{bmatrix} \ \ \underrightarrow {p} \ \ \begin{bmatrix} t_1: & t_{11} & t_{12} & \cdots & t_{1m} \\ t_2: & t_{21} & t_{22} & \cdots & t_{2m} \\ t_3: & t_{31} & t_{32} & \cdots & t_{3m} \\ \vdots & \vdots & \vdots & \vdots \ \vdots & \vdots \\t_n: & t_{n1} & t_{n2} & \cdots & t_{nm} \end{bmatrix}=T$

  $s_{i,j}\ \underrightarrow {p} \ t_{i,p_j}$;

  对于 S 中的第 j 列,经过映射变成 T 中的第 pj 列;

  可以将 S,T 中的各个列以字符串的形式存下来;

  对于 Sj ,判断 T 中是否存在未被标记 Sj,如果存在,找出字典序最小的那个对应过去即可,并标记;

  如果不存在,输出 -1;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define fi first
 4 #define se second
 5 const int maxn=60;
 6 
 7 int n,m;
 8 char s[maxn];
 9 int ans[maxn];
10 pair<string ,int >f[maxn],g[maxn];
11 
12 void Solve()
13 {
14     ///f,g分别拍完序后,第i个的first要对应才有解
15     for(int i=1;i <= m;++i)
16         if(f[i].fi != g[i].fi)
17             return puts("-1"),void(0);
18 
19     for(int i=1;i <= m;++i)
20         ans[f[i].se]=g[i].se;
21 
22     for(int i=1;i <= m;++i)
23         printf("%d%c",ans[i],i == m ? '\n':' ');
24 }
25 int main()
26 {
27     int T;
28     scanf("%d",&T);
29     while(T--)
30     {
31         scanf("%d%d",&n,&m);
32 
33         for(int i=1;i <= m;++i)
34             f[i]=g[i]=make_pair("",i);
35 
36         for(int i=1;i <= n;++i)
37         {
38             scanf("%s",s+1);
39             for(int j=1;j <= m;++j)
40                 f[j].fi += s[j];
41 
42             scanf("%s",s+1);
43             for(int j=1;j <= m;++j)
44                 g[j].fi += s[j];
45         }
46 
47         sort(f+1,f+m+1);
48         sort(g+1,g+m+1);
49 
50         Solve();
51     }
52     return 0;
53 }
O(n·m)

•感想

  比赛的时候搜索,TLE,并未想到如果 S 中的第 j 列在 T 中找到一个满足的时候就找到当前 j 的对应列;

  并且以后在查找的时候,之前找到的列并不影响答案的正确性,由此衍生出了 O(n·m2) 的解法;

  而上述解法是在参阅了 rank1 的代码后提取出的思路,tql;

 1 #include<bits/stdc++.h> 
 2 #define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
 3 #define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
 4 #define pii pair<int,int>
 5 #define pll pair<ll,ll>
 6 #define ll long long
 7 #define fi first
 8 #define se second
 9 #define PB push_back
10 #define uint unsigned
11 #define ull unsigned ll 
12 using namespace std;
13 pll hsh1[55],hsh2[55];
14 int n,m,ans[55];
15 char s[55];
16 void solve(){
17     scanf("%d%d",&n,&m);
18     For(i,1,m) hsh1[i]=hsh2[i]=pll(0,i);
19     For(i,1,n){
20         scanf("%s",s+1);
21         For(j,1,m) hsh1[j].fi=hsh1[j].fi*233+s[j];
22         scanf("%s",s+1);
23         For(j,1,m) hsh2[j].fi=hsh2[j].fi*233+s[j];
24     }
25     sort(hsh1+1,hsh1+m+1);
26     sort(hsh2+1,hsh2+m+1);
27     For(i,1,m)
28         if (hsh1[i].fi!=hsh2[i].fi)
29             return puts("-1"),void(0);
30     For(i,1,m)
31         ans[hsh1[i].se]=hsh2[i].se;
32     For(i,1,m) printf("%d%c",ans[i],i==m?'\n':' ');
33 }
34 int main(){
35     int T;
36     scanf("%d",&T);
37     while (T--) solve(); 
38 }
O(n·m),字符串哈希

 

posted @ 2019-08-19 16:41  HHHyacinth  阅读(263)  评论(0编辑  收藏  举报