【USACO 11 FEB】牛線Cow Line
阿新 • • 發佈:2018-12-17
【題目】
題目描述:
( ≤ ≤ ) 頭牛,編號為 ,正在與 FJ 玩一個瘋狂的遊戲。奶牛會排成一行(牛線),問 FJ 此時的行號是多少。之後,FJ 會給牛一個行號,牛必須按照新行號排列成線。
行號是通過以字典序對行的所有排列進行編號來分配的。比如說:FJ 有 頭牛,讓他們排為行號 ,排列順序為:
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 可以看到這裡的答案是 。
FJ 和奶牛希望你的幫助玩他們的遊戲。他們需要 ( ≤ ≤ )組查詢,查詢有兩個部分: 將是"P"或"Q"的命令。
如果 是"P",則查詢的第二部分將是一個整數 ( ≤ ≤ ),它是行號。此時,你需要回答正確的牛線。
如果 是"Q",則查詢的第二部分將是 個不同的整數 ( ≤ ≤ )。這將表示一條牛線,此時你需要輸出正確的行號。
樣例資料:
輸入 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;
}