1. 程式人生 > >【USACO 11 FEB】牛線Cow Line

【USACO 11 FEB】牛線Cow Line

【題目】

傳送門

題目描述:

nn11nn2020) 頭牛,編號為 1...n1...n,正在與 FJ 玩一個瘋狂的遊戲。奶牛會排成一行(牛線),問 FJ 此時的行號是多少。之後,FJ 會給牛一個行號,牛必須按照新行號排列成線。

行號是通過以字典序對行的所有排列進行編號來分配的。比如說:FJ55 頭牛,讓他們排為行號 33,排列順序為:

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 可以看到這裡的答案是 55

FJ 和奶牛希望你的幫助玩他們的遊戲。他們需要 kk11kk1000010000)組查詢,查詢有兩個部分:cic_i 將是"P"或"Q"的命令。

如果 cic_i 是"P",則查詢的第二部分將是一個整數 aia_i11aia_in!n!),它是行號。此時,你需要回答正確的牛線。

如果 cic_i 是"Q",則查詢的第二部分將是 nn 個不同的整數 bi,jb_{i,j}11bi,jb_{i,j}nn)。這將表示一條牛線,此時你需要輸出正確的行號。

樣例資料:

輸入 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; }