Intro
- 来源:E.Ethernet - Codeforces
- 题意:给定 n ( 1 ≤ n ≤ 10 ) n(1\le n\le 10) n(1≤n≤10) 个数组成的排列,其中前 m ( 0 ≤ m ≤ n ) m(0\le m\le n) m(0≤m≤n) 个数(即 1 1 1~ m m m) 在排列中位置随机,对于剩余 n − m n-m n−m 个数,设当前填充数字为 i ( n − m ≤ i ≤ n ) i(n-m\le i\le n) i(n−m≤i≤n):
- 若第 i i i 位未被填充,则填充数字 i i i;
- 否则, i i i 将被随机填充到先前未被填充的位上。
- 关键词:搜索,思维(签到)
题解
下面给出两种解法:
DFS
注意到 n = 10 n=10 n=10,显而易见这是一道DFS板子题,不需要任何剪枝技巧,复杂度 O ( n ! ) O(n!) O(n!)。
cpp
#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,yes;
vector<bool>v(11);
void dfs(int x){//x:当前处理数字
if(x==n){//插满
cnt++;
if(!v[n]) yes++;
}else if(x>m){//乱插结束
if(!v[x]){
v[x]=1;
dfs(x+1);
v[x]=0;
}else{//乱插
for(int i=1;i<=n;i++)
if(!v[i]){
v[i]=1;
dfs(x+1);
v[i]=0;
}
}
}else{
for(int i=1;i<=n;i++)
if(!v[i]){
v[i]=1;
dfs(x+1);
v[i]=0;
}
}
}
void solve(){
cin>>n>>m;
dfs(1);
printf("%.10lf",yes/(double)cnt);
}
signed main(){
// ios::sync_with_stdio(0),cin.tie(0);
int t=1;
while(t--) solve();
return 0;
}
结论
手玩几个样例,不难发现:
若 n = m n=m n=m,则答案为 1 m \frac{1}{m} m1;否则答案为 1 m + 1 \frac{1} {m+1} m+11。
cpp
#include<bits/stdc++.h>
using namespace std;
int n,k;
void solve(){
if(n==k) printf("%.10lf",1/(double)k);
else printf("%.10lf",1/(double)(k+1));
}
signed main(){
scanf("%lld %lld",&n,&k);
solve();
return 0;
}