Pro
Sol
哇哇哇,昨晚调了一个小时没调出来,今天早上调了一会就出来了坑点不算很多,只是我比较粗心……
拿到题,一眼肯定想到和排列组合有关的知识,其实用到的也不是太多,首先对于单词的存储,我们想方设法的把每一行和每一列的单词都分别存下来,以后都会调用到的。然后预处理出第 i i 列第行后面有多少种可能性放到 qc q c 数组中,递推公式:
在预处理之前呢,我们求出每一列不同的单词数量,存到 cnt c n t 数组中,可以排好序之后用类似栈的做法做,不多解释了,截止到现在,排列组合的知识已经全部用完~
然后,我们求如果没有删除(在所有的牛中去掉没有的牛)操作,我们要查询的 K K 所对应的位置。什么叫对应的位置呢?就是开始我们的状压了:对于每一列,每一个单词都标记一下,该单词是这一列的第几个单词。那么我们第一次求的位置的时候,就能把求得的这些位置存到 Knum K n u m 数组中。
接下来就是删除操作,所谓删除,其实我们可以理解为:如果有比
K
K
的位置小的数,我们就把往后移。应该很容易理解吧。于是我们就枚举每一行,把每一行的几个单词对应的位置处理出来,存到
Pnum
P
n
u
m
数组中,用
sol
s
o
l
函数进行比较,如果比
K
K
的位置要小,就后移。最后
Knum
K
n
u
m
中的数就是我们答案在他所在列的位置,输出就好了。
再说说把单词转化为位置的做法,刚才我们维护了第 i i 行第列后面的可能性。我们每一列每一列的求,对于每一列,枚举他的每一行,如果从枚举到的这一行向上,所有可能性的总和比我们要查的位置要大,我们就取这一行,更新我们要查的位置,更新的时候一定要记得乘上行数减一!
几个易错的地方:
1.最后比较每一行与 K K 所对应的位置的时候,一位一位的比较,发现小的,立即停止,注意,不是,是 return r e t u r n ,因为题目中可能会有比较的两个字符串每一个位置对应相等的情况,因此在最后打上标记就行。
2.把每一个单词转化为每一列的第几个单词的时候,注意两个地方,第一个就是相等的情况,如果相等,后面的直接取最后一行;第二种是最后一列的时候,直接就可以赋值。
Code
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
struct Letr {
int group;
string adj;
bool operator < (const Letr &a) const {
return adj < a.adj;
}
};
Letr adj[30005];
vector<string>str[350];
int n , k , num , top = 0 , cnt[350] , qc[350][1050], knum[350] , pnum[350], flag;
string gro[350][1050];
int jud(string s) {
if(s != "Farmer" && s != "John" && s != "has" && s != "no" && s != "cow.")
return 1;
return 0;
}
void update(int t) {
for(int i=1; i<num; i++) {
int sum = 0;
for(int j=1; j<=cnt[i]; j++) {
sum += qc[i][j];
if(sum == t) {
knum[i] = j;
for(int l=i+1; l<=num; l++)
knum[l] = cnt[i];
return ;
}
if(sum > t) {
knum[i] = (j-1<1)?1:j;
t -= (qc[i][(j-1<1)?1:(j-1)]*(j-1));
break;
}
}
}
knum[num] = t;
}
void sol(int x[] , int y[]) {
for(int i=1; i<=num; i++) {
if(x[i] > y[i])
return;
if(x[i] < y[i]) {
flag = 1;
return;
}
}
flag = 1;
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++) {
string s;
num = 0;
while(1) {
cin>>s;
if(jud(s)) {
num++;
str[i].push_back(s);
adj[++top].adj = s;
adj[top].group = num;
}
if(s == "cow.")
break;
}
}
sort(adj , adj+top+1);
for(int i=1; i<=top; i++) {
if(adj[i].adj == adj[i-1].adj && adj[i].group == adj[i-1].group)
continue;
gro[adj[i].group][++cnt[adj[i].group]] = adj[i].adj;
}
for(int i=1; i<=n; i++)
qc[num][i] = 1;
for(int i=num-1; i>=1; i--)
for(int j=1; j<=n; j++)
qc[i][j] = qc[i+1][j]*cnt[i+1];
update(k);
for(int i=1; i<=n; i++) {
flag = 0;
for(int j=0; j<str[i].size(); j++) {
for(int l=1; l<=cnt[j+1]; l++) {
if(str[i][j] == gro[j+1][l]) {
pnum[j+1] = l;
break;
}
}
}
sol(pnum , knum);
if(flag) {
k++;
update(k);
}
}
for(int i=1; i<=num; i++)
cout<<gro[i][knum[i]]<<" ";
return 0;
}