子曰:“不得中行而于之,
必也狂乎!狂者进取,
狷者有所不为也。"
孔子说:”找不到行为合乎中庸的人而和他们交往,一定只能和勇于向前和洁身自好的人交往!勇于向前的人努力进取,洁身自好的人守规矩。
本文讲述牛客周赛40。
结论题,这题的n都是偶数。
我们使用贪心的思想填补。
因为无论n是哪个偶数,可以确定的是,一定有一种方案,使得能用第二种方案完美地填补所有的格子。
分为两个情况,一种情况是n能整除3。
如果n能整除3,毫无疑问,
当然,在这种情况下,如果用第一种格子填补,我们会出现这样的填补方案。
这时候,我们要考虑混搭的情况,也就是使用第一个格子,又使用第二个格子,是否是一个不错的解法。
如果n不整除3的情况下,第二个格子依然能完美地填补,但是第一个格子却不能填补。
先了解条件期望
这道题涉及到决策,并且肯定在第一轮做出决策。
如果不选择我们的期望是容易算出来的。
#include<bits/stdc++.h>
using namespace std;
double a[200010];
double sum[2000010];
signed main()
{
long long n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
double s=0;
for(int i=0;i<n;i++)
s+=a[i];
if(n<=2)return cout<<s,0;
for(int i=n-1;i>=0;i--)
{
sum[i]=a[i]+sum[i+1];//后缀和
}
double avg=s/n*2;
double res=0;
for(int i=0;i<n;i++)
{
double temp=(s-a[i])/(n-1);
int id=lower_bound(a,a+n,temp)-a;
double E=sum[id]+temp*id;
//减少枚举到a[i]
if(a[i]>=temp)E-=a[i];//如果a[i]比较大,那么我们会多枚举a[i]
else //否则,我们会多枚举temp
E-=temp;
E/=(n-1);
res+=max(avg,E+a[i]);
}
printf("%.7f",res/n);
}
有一种类似于和自然博弈的思想,高楼扔鸡蛋。
https://leetcode.cn/problems/super-egg-drop
这种做法是超时的,但是为什么我们还需要提这种做法?
因为这种做法是通用的。
#include<bits/stdc++.h>
using namespace std;
#define double long double
const int N=100010;
int a[N];
int n;
double dp[N][3][3];
bool st[N][3][3];
double dfs(int id,int has,int los)
{
if(has==2)return 0.l;
if(st[id][has][los])return dp[id][has][los];
st[id][has][los]=true;
for(int i=1;i<=n;i++)
{
if(i==id)continue;
if(los==0)
{
dp[id][has][los]+=max(dfs(i,has+1,los)+a[i],dfs(id,has,los+1))/(n-has);
}
else
{
dp[id][has][los]+=(a[i]+dfs(i,has+1,los))/(n-has);
}
}
return dp[id][has][los];
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
if(n==1)
{
cout<<a[1];
return 0;
}
if(n==2)
{
cout<<a[1]+a[2];
return 0;
}
double res=dfs(0,0,0);
printf("%.10Lf\n",res);
}
这种形式可以用在许多题目上,
#include<bits/stdc++.h>
using namespace std;
double f[103][103][103];
double dp(int a,int b,int c)
{
if(a>=100||b>=100||c>=100)
return 0;
if(f[a][b][c]>0)return f[a][b][c];
double res=0;
res+=(dp(a+1,b,c)+1)*(double)a/(a+b+c);
res+=(1+dp(a,b+1,c))*(double)b/(a+b+c);
res+=(1+dp(a,b,c+1))*(double)c/(a+b+c);
return f[a][b][c]=res;
}
signed main()
{
int a,b,c;
cin>>a>>b>>c;
printf("%.8f",dp(a,b,c));
}
但是,有些时候状态转移会形成一个环,我们有些时候输出无解,有些时候要通过代数变形。
有环的动态规划
通过代数变形处理的动态规划全期望公式|概率|程序设计|算法