【USACO 11 FEB】牛线Cow Line

xiaoxiao2025-09-18  21

【题目】

传送门

题目描述:

n n n 1 1 1 n n n 20 20 20) 头牛,编号为 1... n 1...n 1...n,正在与 FJ 玩一个疯狂的游戏。奶牛会排成一行(牛线),问 FJ 此时的行号是多少。之后,FJ 会给牛一个行号,牛必须按照新行号排列成线。

行号是通过以字典序对行的所有排列进行编号来分配的。比如说:FJ 5 5 5 头牛,让他们排为行号 3 3 3,排列顺序为:

1:1 2 3 4 5 2:1 2 3 5 4 3:1 2 4 3 5

因此,牛将在牛线 1 2 4 3 5 中。

之后,奶牛排列为"1 2 5 3 4",并向 FJ 问他们的行号。继续列表:

4:1 2 4 5 3 5:1 2 5 3 4

FJ 可以看到这里的答案是 5 5 5

FJ 和奶牛希望你的帮助玩他们的游戏。他们需要 k k k 1 1 1 k k k 10000 10000 10000)组查询,查询有两个部分: c i c_i ci 将是"P"或"Q"的命令。

如果 c i c_i ci 是"P",则查询的第二部分将是一个整数 a i a_i ai 1 1 1 a i a_i ai n ! n! n!),它是行号。此时,你需要回答正确的牛线。

如果 c i c_i ci 是"Q",则查询的第二部分将是 n n n 个不同的整数 b i , j b_{i,j} bi,j 1 1 1 b i , j b_{i,j} bi,j n n n)。这将表示一条牛线,此时你需要输出正确的行号。

样例数据:

输入 5 2 P 3 Q 1 2 5 3 4

输出 1 2 4 3 5 5

【分析】

题解:康拓展开模板题

直接套用模板就可以解这道题了

贴一个同学的代码吧康拓展开&逆康拓展开

【代码】

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 25 #define ll long long using namespace std; int n,m,a[N]; bool vis[N]; ll fac[N]; ll cantor() { ll ans=0; for(int i=1;i<=n;++i) { int num=0; for(int j=i+1;j<=n;++j) if(a[j]<a[i]) num++; ans+=fac[n-i]*num; } return ans; } void reverse_cantor(ll x) { int i,j;x--; memset(vis,false,sizeof(vis)); for(i=1;i<=n;++i) { int num=x/fac[n-i]; for(j=1;j<=n;++j) if(!vis[j]&&!num--) break; a[i]=j; vis[j]=true; x%=fac[n-i]; } } int main() { int i,j; char c;ll x; scanf("%d%d",&n,&m); fac[0]=fac[1]=1; for(i=2;i<=n;++i) fac[i]=fac[i-1]*i; for(i=1;i<=m;++i) { cin>>c; if(c=='P') { scanf("%lld",&x); reverse_cantor(x); for(j=1;j<=n;++j) printf("%d ",a[j]); printf("\n"); } else { for(j=1;j<=n;++j) scanf("%d",&a[j]); x=cantor()+1; printf("%lld\n",x); } } return 0; }
转载请注明原文地址: https://www.6miu.com/read-5036570.html

最新回复(0)