这场没打,那就尽快补救回来吧
A. New Year and Counting Cards
签到
B. New Year and Buggy Bot
全排列一下即可,可以用next_permation或者dfs枚举全排列
C. New Year and Curling
题意
给n个半径为r的小球,可以看做从无限高垂直落下,每个小球落下的横坐标为xi,按顺序一个一个放下小球,如果一个小球碰到另一个小球就停止运动
问最后每个小球的高度
分析
直接暴力枚举找到相碰的最高高度即可
时间复杂度O(n^2)
#include<bits/stdc++.h> using namespace std; int h[1500]; double res[1500]; int abs(int x,int y) {if(x - y > 0) return x - y;return y - x;} int main(){ ios_base::sync_with_stdio(0); int n; double r; cin>>n>>r; for(int i = 0;i < n;i++) { cin>>h[i]; double rs = r; for(int j = 0;j < i;j++) { int dx = abs(h[i],h[j]); if(dx <= 2*r) { rs = max(rs,res[j] + sqrt(4*r*r - dx*dx)); } } res[i] = rs; } for(int i = 0;i < n;i++) printf("%.10f ",res[i]); return 0; }
D. New Year and Arbitrary Arrangement
题意
给三个数k,pa,pb,每次有pa/(pa+pb)的概率向字符串末尾添加一个a,有pb/(pa+pb)的概率向字符串末尾添加一个b, 当这个字符串的子序列ab的数量>=k,就停止添加,问最后ab子序列数量的期望值 (1 ≤ k ≤ 1 000, 1 ≤ pa, pb ≤ 1 000 000)
分析
概率dp!!!
概率DP主要用于求解期望、概率等题目。转移方程有时候比较灵活,一般求概率是正推,求期望是逆推 -----kuangbin
定义:dp[i][j]:表示在串中有i个a,j个ab时开始加字符直到停止的期望ab个数
转移方程:dp[i][j] = ( pa*dp[i+1]][j] + pb*dp[i][i+j] )*(pa+pb)
答案:dp[1][0]即为所求。因为在第一个a出现之前,无论有多少b,ab数量都不会变与,只有当出现第一个a时,我们加入b才会产生ab
首先(j>=k):有一个显然的状态:dp[i][j] = j (j>=k)
然后(i+j>=k && j<k): 此时只需要一个b就停止添加
此时考虑添加b之前添加a的数量的期望值(设为ans),设p=pa /(pa+pb) (以下图片来自他人CSDN博客)
所以 当(i+j>=k) : dp[i][j]=i+j+pa/pb
所以剩下的就是逆推出dp[1][0]的期望值即可
时间复杂度O(k^2)
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1005; const ll mod=1e9+7; int k, pa, pb; int dp[maxn][maxn]; long long inv (int x) { return x==1?1:(mod-mod/x)*inv(mod%x)%mod; } int Dp(int i,int j) { if(dp[i][j]) return dp[i][j]; if(i+j>=k) return dp[i][j]=(i+j+1ll*pa*inv(pb)%mod)%mod; else return dp[i][j]=((1ll*pa*Dp(i+1,j)%mod+1ll*pb*Dp(i,i+j)%mod)*inv(pa+pb))%mod; } int main() { scanf("%d%d%d", &k, &pa, &pb); printf("%d\n", Dp(1,0)); return 0; }
E. New Year and Entity Enumeration
贝尔数问题
例题:集合划分
F. New Year and Rainbow Roads
题意
给你n个点,每个点都是red,blue,green三种颜色之一,每个点都在x轴上的一个点,要求把它们连成一张图,使得去掉所有的red点,剩下blue和green点仍然是一张图,同理去掉blue,连接任意两个点的代价是这两个点的距离,问满足题意的最小花费(按照x递增的顺序给出这n个点)
分析
首先可以看出,red和green之间不可能存在边,因为看不到
不难看出,red green red这种情况下,连接两个red,和red-green-red的代价是等效的(同理,blue green blue也是的),所以考虑以green为分界点,分段即可,具体细节还需要考虑一下,要注意一下没有green点情况
时间复杂度O(n)
#include<bits/stdc++.h> using namespace std; #define mz 1000000007 #define pq priority_queue char s[6]; int main() { int n,now,maxxb=0,maxxr=0; int ans=0; int preg,prer,preb; preg=prer=preb=-1; int minr,minb,ming; minr=minb=ming=mz; int maxr,maxb,maxg; maxr=maxb=maxg=-1; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&now); scanf("%s",s); if(s[0]=='G') { ming=min(now,ming); maxg=max(now,maxg); if(preg!=-1) { ans+=now-preg; maxxb=max(maxxb,now-preb); maxxr=max(maxxr,now-prer); ans+=min((now-preg)*2-maxxr-maxxb,now-preg); } maxxr=maxxb=0; prer=preb=preg=now; } if(s[0]=='B') { minb=min(now,minb); maxb=max(now,maxb); maxxb=max(maxxb,now-preb); preb=now; } if(s[0]=='R') { minr=min(now,minr); maxr=max(now,maxr); maxxr=max(maxxr,now-prer); prer=now; } } if(ming==mz) { if(minr<maxr) ans+=maxr-minr; if(minb<maxb) ans+=maxb-minb; } else { if(minb<ming) ans+=ming-minb; if(minr<ming) ans+=ming-minr; if(maxb>maxg) ans+=maxb-maxg; if(maxr>maxg) ans+=maxr-maxg; } printf("%d\n",ans); return 0; }
样例:
input:
6
1 G
2 B
3 R
4 B
5 R
6 G
ouput:
10