T1 洛谷 P3014 [USACO11FEB]牛线Cow Line
题目背景
征求翻译。如果你能提供翻译或者题意简述,请直接发讨论,感谢你的贡献。
题目描述
The N (1 <= N <= 20) cows conveniently numbered 1...N are playing yet another one of their crazy games with Farmer John. The cows will arrange themselves in a line and ask Farmer John what their line number is. In return, Farmer John can give them a line number and the cows must rearrange themselves into that line.
A line number is assigned by numbering all the permutations of the line in lexicographic order.
Consider this example:
Farmer John has 5 cows and gives them the line number of 3.
The permutations of the line in ascending lexicographic order: 1st: 1 2 3 4 5
2nd: 1 2 3 5 4
3rd: 1 2 4 3 5
Therefore, the cows will line themselves in the cow line 1 2 4 3 5.
The cows, in return, line themselves in the configuration '1 2 5 3 4' and ask Farmer John what their line number is.
Continuing with the list:
4th : 1 2 4 5 3
5th : 1 2 5 3 4
Farmer John can see the answer here is 5
Farmer John and the cows would like your help to play their game. They have K (1 <= K <= 10,000) queries that they need help with. Query i has two parts: C_i will be the command, which is either 'P' or 'Q'.
If C_i is 'P', then the second part of the query will be one integer A_i (1 <= A_i <= N!), which is a line number. This is Farmer John challenging the cows to line up in the correct cow line.
If C_i is 'Q', then the second part of the query will be N distinct integers B_ij (1 <= B_ij <= N). This will denote a cow line. These are the cows challenging Farmer John to find their line number.
输入输出格式
输入格式:
-
Line 1: Two space-separated integers: N and K
- Lines 2..2*K+1: Line 2*i and 2*i+1 will contain a single query.
Line 2*i will contain just one character: 'Q' if the cows are lining up and asking Farmer John for their line number or 'P' if Farmer John gives the cows a line number.
If the line 2*i is 'Q', then line 2*i+1 will contain N space-separated integers B_ij which represent the cow line. If the line 2*i is 'P', then line 2*i+1 will contain a single integer A_i which is the line number to solve for.
输出格式:
- Lines 1..K: Line i will contain the answer to query i.
If line 2*i of the input was 'Q', then this line will contain a single integer, which is the line number of the cow line in line 2*i+1.
If line 2*i of the input was 'P', then this line will contain N space separated integers giving the cow line of the number in line 2*i+1.
输入输出样例
5 2 P 3 Q 1 2 5 3 4
1 2 4 3 5 5
康托展开:
1 #include <algorithm> 2 #include <string> 3 #include <cstdio> 4 #include <map> 5 6 using namespace std; 7 8 #define LL long long 9 LL jc[21]={1,1,2,6,24,120,720,5040,40320,362880,328800, 10 39916800,479001600,6227020800LL,87178291200LL, 11 1307674368000LL,20922789888000LL,355687428096000LL, 12 6402373705728000LL,121645100408832000LL,2432902008176640000LL}; 13 map<LL,string>m1; 14 map<string,LL>m2; 15 LL n,m,x,cnt,tmp[26]; 16 char num[26],sta[26]; 17 string a; 18 19 inline void read(LL &x) 20 { 21 x=0; register char ch=getchar(); 22 for(;ch>'9'||ch<'0';) ch=getchar(); 23 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 24 } 25 26 void work1() 27 { 28 for(int i=1; i<=n; ++i) num[i-1]=i+'0'; 29 for(;1;next_permutation(num,num+n)) 30 { 31 if(m2[num]) break; 32 m1[++cnt]=num; 33 m2[num]=cnt; 34 } 35 for(char s[2];m--;) 36 { 37 scanf("%s",s); 38 if(s[0]=='P') 39 { 40 read(x); a=m1[x]; 41 for(int i=0;i<n-1;i++) 42 printf("%d ",a[i]-'0'); 43 printf("%d\n",a[n-1]-'0'); 44 } 45 else 46 { 47 for(int i=0; i<n; ++i) 48 read(x),a[i]=x+'0'; 49 printf("%lld\n",m2[a]); 50 } 51 } 52 } 53 54 int AC() 55 { 56 // freopen("permutation.in","r",stdin); 57 // freopen("permutation.out","w",stdout); 58 59 read(n),read(m); 60 /*jc[0]=1; 61 for(LL i=1; i<=n; ++i) jc[i]=jc[i-1]*i;*/ 62 if(n<=5) work1(); 63 else 64 { 65 for(char s[2];m--;) 66 { 67 scanf("%s",s); 68 if(s[0]=='P') 69 { 70 read(x); x--; 71 bool use[26]={0}; 72 for(LL j,i=1; i<=n; ++i) 73 { 74 LL tmp=x/jc[n-i]; 75 for(j=1; j<=n; ++j) 76 if(!use[j]) 77 { 78 if(!tmp) break; 79 tmp--; 80 } 81 use[j]=1; 82 x%=jc[n-i]; 83 printf("%d ",j); 84 } 85 puts(""); 86 } 87 else 88 { 89 for(LL i=1; i<=n; ++i) read(tmp[i]); 90 LL ans=0; 91 for(LL t=0,i=1;i<=n;i++) 92 { 93 t=0; 94 for(LL j=i+1; j<=n; ++j) 95 if(tmp[i]>tmp[j]) t++; 96 ans+=t*jc[n-i]; 97 } 98 printf("%I64d\n",ans+1); 99 } 100 } 101 } 102 return 0; 103 } 104 105 int Hope=AC(); 106 int main(){;}
阶乘没打表就能过了、、
1 #include <cstdio> 2 3 using namespace std; 4 5 #define LL long long 6 LL jc[21]; 7 LL n,m,x,cnt,tmp[26]; 8 9 inline void read(LL &x) 10 { 11 x=0; register char ch=getchar(); 12 for(;ch>'9'||ch<'0';) ch=getchar(); 13 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 14 } 15 16 int AC() 17 { 18 // freopen("permutation.in","r",stdin); 19 // freopen("permutation.out","w",stdout); 20 21 read(n),read(m); 22 jc[0]=1; for(LL i=1; i<=n; ++i) jc[i]=jc[i-1]*i; 23 for(char s[2];m--;) 24 { 25 scanf("%s",s); 26 if(s[0]=='P') 27 { 28 read(x); x--; 29 bool use[26]={0}; 30 for(LL j,i=0; i<n; ++i) 31 { 32 LL tmp=x/jc[n-i-1]; 33 for(j=1; j<=n; ++j) 34 if(!use[j]) 35 { 36 if(!tmp) break; 37 tmp--; 38 } 39 use[j]=1; 40 x%=jc[n-i-1]; 41 printf("%d ",j); 42 } 43 puts(""); 44 } 45 else 46 { 47 for(LL i=0; i<n; ++i) read(tmp[i]); 48 LL ans=0; 49 for(LL t=0,i=0;i<n;i++) 50 { 51 t=0; 52 for(LL j=i+1; j<n; ++j) 53 if(tmp[i]>tmp[j]) t++; 54 ans+=t*jc[n-i-1]; 55 } 56 printf("%lld\n",ans+1); 57 } 58 } 59 return 0; 60 } 61 62 int Hope=AC(); 63 int main(){;}
T2 洛谷 U3357 C2-走楼梯
题目背景
在你成功地解决了上一个问题之后,方方方不禁有些气恼,于是他在楼梯上跳来跳去,想要你求出他跳的方案数。..
题目描述
方方方站在一个n阶楼梯下面,他每次可以往上跳一步或两步,往下跳一步到四步(由于地心引力跳得比较远),而且在往下跳的时候你只能踩在你往上跳时踩过的格子。
现在方方方在楼梯上乱跳,想问他跳到楼梯顶上最后又跳回楼梯下面的方案数mod 2333333。
请注意:针对题目有歧义的情况,这里再说明一下。方方方只能一直向上跳,跳到楼梯最上面,然后再往下跳,跳回楼梯最底下。
输入输出格式
输入格式:
输入一行一个数n。
输出格式:
输出方方方跳回楼梯下面的方案数mod 2333333。
输入输出样例
5
52
7654321
451197
3
8
说明
对于30%的数据,n<=10。
对于100%的数据,1<=n<=10^7。
(其实也可以做到10^18,可是出题人懒)
1 #include <cstdio> 2 3 const int mod(2333333); 4 const int N(1e7+5); 5 int n; 6 7 inline void read(int &x) 8 { 9 x=0; register char ch=getchar(); 10 for(;ch>'9'||ch<'0';) ch=getchar(); 11 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 12 } 13 14 int ans; 15 bool vis[N],vis_[N]; 16 void DFS_(int now) 17 { 18 if(now==0) 19 { 20 ans++; 21 ans%=mod; 22 return ; 23 } 24 for(int i=1; i<=4; ++i) 25 { 26 if(vis_[now-i]||(now-i<0)) continue; 27 if(!vis[now-i]) continue; 28 vis_[now-i]=1; 29 DFS_(now-i); 30 vis_[now-i]=0; 31 } 32 } 33 void DFS(int now) 34 { 35 if(now==n) 36 { 37 DFS_(now); 38 return ; 39 } 40 for(int i=1; i<=2; ++i) 41 { 42 if(vis[now+i]||(now+i>n)) continue; 43 vis[now+i]=1; 44 DFS(now+i); 45 vis[now+i]=0; 46 } 47 } 48 49 int AC() 50 { 51 // freopen("stair.in","r",stdin); 52 // freopen("stair.out","w",stdout); 53 54 read(n); vis[0]=1; DFS(0); 55 printf("%d\n",ans); 56 return 0; 57 } 58 59 int Hope=AC(); 60 int main(){;}
正解DP:
向下走可以看成向上走
f[i]表示第一次向上走到i,第二次向上也走到i的方案数
如果第二次向上走1步到i,这1步第一次有1种走法
如果第二次向上走2步到i,这2步第一次有2种走法
如果第二次向上走3步到i,这3步第一次有3种走法
如果第二次向上走4步到i,这4步第一次有5种走法
所以状态转移方程:f[i]=f[i-1]+f[i-2]*2+f[i-3]*3+f[i-4]*5
1 #include <cstdio> 2 3 const int mod(2333333); 4 const int N(1e7+5); 5 int n,f[N]; 6 7 inline void read(int &x) 8 { 9 x=0; register char ch=getchar(); 10 for(;ch>'9'||ch<'0';) ch=getchar(); 11 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 12 } 13 14 int AC() 15 { 16 read(n); 17 f[0]=1; f[1]=1; f[2]=3; f[3]=8; 18 for(int i=4;i<=n;i++) 19 f[i]=(f[i-1]+f[i-2]*2+f[i-3]*3+f[i-4]*5)%mod; 20 printf("%d\n",f[n]); 21 return 0; 22 } 23 24 int Hope=AC(); 25 int main(){;}
T3 BZOJ——1821: [JSOI2010]Group 部落划分 Group
Description
聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。 不过好消息是,聪聪得到了一份荒岛的地图。地图上标注了N个野人居住的地点(可以看作是平面上的坐标)。我们知道,同一个部落的野人总是生活在附近。我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。聪聪还获得了一个有意义的信息——这些野人总共被分为了K个部落!这真是个好消息。聪聪希望从这些信息里挖掘出所有部落的详细信息。他正在尝试这样一种算法: 对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。 例如,下面的左图表示了一个好的划分,而右图则不是。请你编程帮助聪聪解决这个难题。
Input
Output
输出一行,为最优划分时,最近的两个部落的距离,精确到小数点后两位。
Sample Input
0 0
0 1
1 1
1 0
Sample Output
HINT
Source
最小生成树+乱搞活似一个大zz
1 #include <algorithm> 2 #include <cstdio> 3 #include <cmath> 4 5 const int N(1026); 6 int n,k,sumedge; 7 struct Node { 8 int x,y; 9 }peo[N]; 10 struct Edge { 11 double dis; 12 int u,v; 13 bool operator < (const Edge x)const 14 { 15 return dis>x.dis; 16 } 17 Edge(int u=0,int v=0,double dis=0.0):u(u),v(v),dis(dis){} 18 }e[N*N]; 19 20 inline void read(int &x) 21 { 22 x=0; register char ch=getchar(); 23 for(;ch>'9'||ch<'0';) ch=getchar(); 24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 25 } 26 27 double Get_dis(int u,int v) 28 { 29 return sqrt((double)(peo[u].x-peo[v].x)*(peo[u].x-peo[v].x)+(double)(peo[u].y-peo[v].y)*(peo[u].y-peo[v].y)); 30 } 31 32 int fa[N]; 33 int find(int x) 34 { 35 return fa[x]==x?x:fa[x]=find(fa[x]); 36 } 37 38 #define max(a,b) (a>b?a:b) 39 #define min(a,b) (a<b?a:b) 40 41 int AC() 42 { 43 freopen("people.in","r",stdin); 44 freopen("people.out","w",stdout); 45 46 read(n),read(k); 47 for(int i=1; i<=n; ++i) 48 read(peo[i].x),read(peo[i].y); 49 for(int i=1; i<=n; ++i) 50 for(int j=1; j<=n; ++j) 51 if(i!=j) e[++sumedge]=Edge(i,j,Get_dis(i,j)); 52 int cnt=0; 53 double ans=0; 54 std::sort(e+1,e+sumedge+1); 55 for(int i=1; i<=n; ++i) fa[i]=i; 56 for(int fx,fy,i=1; i<=sumedge; ++i) 57 { 58 fx=find(e[i].u), fy=find(e[i].v); 59 if(fa[fx]==fy) continue; 60 fa[fx]=fy; 61 if(++cnt<=k) ans=max(ans,e[i].dis); 62 else ans=min(ans,e[i].dis); 63 if(cnt==n-1) break; 64 } 65 printf("%.2lf",ans); 66 return 0; 67 } 68 69 int Hope=AC(); 70 int main(){;}
最小生成树:
首先按照边权排序,要让最小的距离最大,那么就让那些很小的距离放在部落内部;
原来有n个部落,而每加入一条边就会减少一个,ans=最小生成树的第n-k+1条边。
1 #include <algorithm> 2 #include <cstdio> 3 #include <cmath> 4 5 const int N(1026); 6 int n,k,sumedge; 7 double dist[N]; 8 struct Node { 9 int x,y; 10 }peo[N]; 11 struct Edge { 12 double dis; 13 int u,v; 14 bool operator < (const Edge &x)const 15 { 16 return dis<x.dis; 17 } 18 Edge(int u=0,int v=0,double dis=0.0):u(u),v(v),dis(dis){} 19 }e[N*N]; 20 21 inline void read(int &x) 22 { 23 x=0; register char ch=getchar(); 24 for(;ch>'9'||ch<'0';) ch=getchar(); 25 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; 26 } 27 28 double Get_dis(int u,int v) 29 { 30 return sqrt((double)(peo[u].x-peo[v].x)*(peo[u].x-peo[v].x)+(double)(peo[u].y-peo[v].y)*(peo[u].y-peo[v].y)); 31 } 32 33 int fa[N]; 34 int find(int x) 35 { 36 return fa[x]==x?x:fa[x]=find(fa[x]); 37 } 38 39 #define max(a,b) (a>b?a:b) 40 #define min(a,b) (a<b?a:b) 41 42 int AC() 43 { 44 // freopen("people.in","r",stdin); 45 // freopen("people.out","w",stdout); 46 47 read(n),read(k); 48 for(int i=1; i<=n; ++i) 49 read(peo[i].x),read(peo[i].y); 50 for(int i=1; i<=n; ++i) 51 for(int j=1; j<=n; ++j) 52 if(i!=j) e[++sumedge]=Edge(i,j,Get_dis(i,j)); 53 int cnt=0; 54 double ans=0; 55 std::sort(e+1,e+sumedge+1); 56 for(int i=1; i<=n; ++i) fa[i]=i; 57 for(int fx,fy,i=1; i<=sumedge; ++i) 58 { 59 fx=find(e[i].u), fy=find(e[i].v); 60 if(fa[fx]==fy) continue; 61 fa[fx]=fy; 62 if(++cnt>n-k) 63 { 64 printf("%.2lf",e[i].dis); 65 return 0; 66 } 67 } 68 return 0; 69 } 70 71 int Hope=AC(); 72 int main(){;}