建造城市

题解

先思考一个简单问题

10个$toot$ 放进5间房屋,每个房屋至少有1个$toot$,方案数

思考:插板法,$10$个$toot$有$9$个缝隙,$5$间房屋转化为$4$个挡板,放在toot缝隙之间得到$C_{9}^{4}$

10个$toot$ 放进$5$间房屋,每个房屋里可以没有$toot$,方案数

思考:插板法使用条件必须是每组至少有1个,那么我们事先在每个房屋中放一个$toot$变成$15$个$toot$放进$5$个房屋,可以插板法,与上一题类似$C_{14}^{4}$

那么应用到这个题上呢?

这个题$toot$加了一个上界,非常棒对不对,我们可以考虑容斥

怎么算$\sum\limits_{i=0}^{i<=n}  {-1}^i *C_{n}^{i}*C_{m-i*k-1}^{n-1}$

前面是枚举的多的城市,后面枚举的是多的,怎么理解呢?

首先我们让$i$个城市提前选出$i*k$ 个 $toot$,假设我们当前是$i==0$,那么我们选出的包含0个不符合情况的,1个不符合情况的,2个不符合情况的,3个不符合情况的------n个

我们只需要简单容斥一下就完了

代码

     #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 10101010
#define mod 998244353
ll ni[A],jie[A];
ll n,m,k;
ll meng(ll x,ll k){ll ans=1;for(;k;k>>=1,x=x*x%mod)if(k&1)ans=ans*x%mod;return ans;
}
ll C(ll n,ll m){return jie[n]*ni[n-m]%mod*ni[m]%mod;
}
int main(){jie[0]=1;for(ll i=1;i<=10000000;i++)jie[i]=jie[i-1]*i%mod;ni[10000000]=meng(jie[10000000],mod-2);for(ll i=9999999;i>=1;i--)ni[i]=ni[i+1]*(i+1)%mod;ni[0]=1;
/*    while(1){ll a,b;scanf("%lld%lld",&a,&b);cout<<C(a,b)<<endl;}
*/    scanf("%lld%lld%lld",&n,&m,&k);ll ans=0,tmp=1;for(ll i=0;i<=n;i++){if(n-1>m-i*k-1) break;ans=(ans+tmp*C(n,i)*C(m-i*k-1,n-1)%mod)%mod;tmp=-tmp;}cout<<(ans+mod)%mod<<endl;
}

轰炸

语文不好被坑了

一句话题解

tarjan缩点+最长链

代码不放了

石头剪刀布

很奇妙的思路,但觉的现在还是似懂非懂的。

首先这个题是先计算所有概率,最后再统计贡献

和以往做的期望题不太一样

这个题没有顺序很恶心,思考换一种方法避免无序带来影响

我们发现如果只开三维,最后根本无法统计答案,统计起来会像一坨

尝试开四维?

$f[i][j][k][4]$

$f[i][j][k][1]$表示已经有$i$个人出石头,$j$个人出剪刀,$k$个人出布,下一轮出石头

$f[i][j][k][2]$表示已经有$i$个人出石头,$j$个人出剪刀,$k$个人出布,下一轮出剪刀

$f[i][j][k][3]$表示已经有$i$个人出石头,$j$个人出剪刀,$k$个人出布,下一轮出布

这样答案转移起来就很好转移了

$ans=\sum\limits _{i=1}^{i<=n} max(f[i][j][k][1]+f[i][j][k][2]*3,f[i][j][k][2]+f[i][j][k][3]*3,f[i][j][k][3]+f[i][j][k][1]*3)$

思考状态转移

直接转移肯定难以转移,开辅助数组$g[i][j][k]$表示出$i$个石头,$j$个剪刀,$k$个布的概率

显然我们可以得到

$f[i][j][k][u]=f[i-1][j][k][u]*x[o][1]+f[i][j-1][k][u]*x[o][2]+f[i][j][k-1][u]*x[o][3]+(x[o][1]+x[o][2]+x[o][3])*g[i][j][k]$

思考这是什么意思

拿1举例,你当前状态已经这样,你又往里面放了一个人,他出了石头,那么当前概率就等于之前的概率*转移过来的概率

下面是迪哥解释

//当u>0时就不太一样了,计算的是接下来出1的概率
        //它由上一轮对方出1的概率乘对方真的出了1的概率累加而来,此时i+j+k!=s
        //因为你把这玩意当成一个背包不断往里面放对手来更新其概率
        //意思大概就是“目前的状态已经是那样了而且下一轮你遇到了s”,然后s对你的概率产生的贡献
        //所以就是你走到原状态的概率,乘上s出1的概率,就是s对目前状态的概率贡献
        //所以i+j+k==s时不能枚举到3,因为相当于你的原状态里面已经有s个人了,可是你现在刚刚开始考虑第s个人啊

细节

你最后统计答案时不能枚举到n因为n没有下一个人了

吴迪带注释代码

#include<bits/stdc++.h>
using namespace std;
//首先题意可能还有人理解错了。题目的意思是你要根据对手分别出了几个石头几个剪刀来决策
//而并不是一场战斗结束后你就能知道对方具体是谁从而直接推断剩下的人
#define d(x,k) for(int x=k;x>=0;--x)//压行,字少
int n;double x[51][4],f[51][51][51][4],ans,c[51][51];
//f数组的含义:当最后一维为1~3时表示第i+j+k+1个人在前面的人出了i个1,j个2,k个3的情况下出1~3的概率
//当最后一维为0时表示前i+j+k个人出了i个1,j个2,k个3的概率,即那个题解里的g数组
int main(){ scanf("%d",&n); f[0][0][0][0]=1;//初始化for(int i=1;i<=n;++i) scanf("%lf%lf%lf",&x[i][1],&x[i][3],&x[i][2]),x[i][1]/=300,x[i][2]/=300,x[i][3]/=300;//读入概率,注意顺序是132。把石头剪刀步分别抽象为123,故1胜2,2胜3,3胜1for(int i=0;i<=50;++i) c[i][0]=1;for(int i=1;i<=50;++i) for(int j=1;j<=i;++j) c[i][j]+=c[i-1][j-1]+c[i-1][j];//杨辉三角。注意:要用到50!级别的而没有取模,所以要开long long或doublefor(int s=1;s<=n;++s) d(i,s) d(j,s-i) d(k,s-i-j) d(u,(i+j+k==s?0:3)){//有点像个背包//你可以把s单独再开一维的数组来表示目前考虑到第几个人,更好理解但貌似会炸内存//u为1~3时,分别枚举第几个人,前面的人出过几个1,2,3,这个人要出u//注意u的枚举是当i+j+k!=s时才更新对方下一次出123的概率,否则只更新到达某状态的概率//u为0时,计算到达这个状态的总概率(即题解中的g数组)if(i)f[i][j][k][u]+=f[i-1][j][k][u]*x[s][1];//这个人s出了1,累加概率//当u=0时,f[i][j][k][0]由f[i-1][j][k][0]转移而来(u=0并不考虑下一个人会出什么)//在原状态出一个1即为新状态,后者的概率为x[s][1]。计算g数组就不必考虑其他f值的影响//因为根据含义就有f[i][j][k][0]=f[i][j][k][1]+f[i][j][k][2]+f[i][j][k][3]//当u>0时就不太一样了,计算的是接下来出1的概率//它由上一轮对方出1的概率乘对方真的出了1的概率累加而来,此时i+j+k!=s//因为你把这玩意当成一个背包不断往里面放对手来更新其概率//意思大概就是“目前的状态已经是那样了而且下一轮你遇到了s”,然后s对你的概率产生的贡献//所以就是你走到原状态的概率,乘上s出1的概率,就是s对目前状态的概率贡献//所以i+j+k==s时不能枚举到3,因为相当于你的原状态里面已经有s个人了,可是你现在刚刚开始考虑第s个人啊if(j)f[i][j][k][u]+=f[i][j-1][k][u]*x[s][2];//出2,同上if(k)f[i][j][k][u]+=f[i][j][k-1][u]*x[s][3];//出3,同if(u)f[i][j][k][u]+=f[i][j][k][0]*x[s][u];//这个就是弥补了上面的缺陷。本层转移。不管目前的状态是什么,反正第s个人就是出u了//与上面的并不重复。一个是在说s对以前的状态的贡献,这个是在说s对当前状态的贡献
    }d(i,n-1) d(j,n-1-i) d(k,n-i-j-1)//i+j+k不要枚举到n,因为已经进行过n轮后下一次再出什么已经不重要不记分了ans+=max(max(f[i][j][k][1]+3*f[i][j][k][2],f[i][j][k][2]+3*f[i][j][k][3]),f[i][j][k][3]+3*f[i][j][k][1])/c[n][i+j+k]/(n-i-j-k);//在每一种状态下(即确定对手已经出了i个1,j个2,k个3)时你都有唯一确定的最优决策来进行下一轮//每一次决策时都会累加分数,3种决策分别对应出1,2,3.f[i][j][k][1]即为与1打平,3*f[i][j][k][2]即为战胜2//你所说的最优决策就是根据已有信息(每个对手出了什么),通过猜测对手下一步会出什么来权衡3中决策//至于为什么用到了组合数:因为你所算的概率只是到达这一步的概率,但是你是从n个人里随便选出了c[n][i+j+k]个人//然而其实在同一场游戏中对于同样的i+j+k你只会选1次,在计算的时候你把概率累加在一起了,现在要求一个平均值//再除一个(n-i-j-k)的原因也差不多,因为你是要从剩下的(n-i-j-k)个人里选出一个去挑战//这一步的概率是1/(n-i-j-k),然而你在上面5层循环的时候并没有考虑,所以在这里统一除去printf("%.12lf\n",ans);//给的std里是用%.12f输出double的,真是惊奇
}//把注释全删掉你就会发现这个代码只有21行811B

View Code

我这个菜鸡的代码

#include<bits/stdc++.h>
using namespace std;
#define A 52
#define ll long long
double f[A][A][A][5],x[A][5];
double ans=0;
ll C[A][A],n;
int main(){f[0][0][0][0]=1;scanf("%lld",&n);for(ll i=0;i<=n;i++)C[i][0]=1;for(ll i=1;i<=n;i++)for(ll j=1;j<=i;j++)C[i][j]=C[i-1][j]+C[i-1][j-1];for(ll i=1;i<=n;i++)scanf("%lf%lf%lf",&x[i][1],&x[i][3],&x[i][2]),x[i][1]/=300,x[i][3]/=300,x[i][2]/=300;for(ll o=1;o<=n;o++){for(ll i=o;i>=0;i--){for(ll j=o-i;j>=0;j--){for(ll k=o-i-j;k>=0;k--){for(ll u=(((i+j+k)==o)?0:3);u>=0;u--){if(i)f[i][j][k][u]+=f[i-1][j][k][u]*x[o][1];if(j)f[i][j][k][u]+=f[i][j-1][k][u]*x[o][2];if(k)f[i][j][k][u]+=f[i][j][k-1][u]*x[o][3];if(u)f[i][j][k][u]+=f[i][j][k][0]*x[o][u];}}}}}for(ll i=n-1;i>=0;i--)for(ll j=n-1-i;j>=0;j--)for(ll k=n-1-i-j;k>=0;k--){ans+=max(max(f[i][j][k][1]+f[i][j][k][2]*3,f[i][j][k][2]+f[i][j][k][3]*3),f[i][j][k][3]+f[i][j][k][1]*3)/C[n][i+j+k]/(n-i-k-j);}printf("%.12lf\n",ans);
}

View Code

转载于:https://www.cnblogs.com/znsbc-13/p/11327441.html

NOIP模拟测试15「建造城市city(插板法)·轰炸·石头剪刀布」相关推荐

  1. NOIP模拟测试24「star way to hevaen·lost my music」

    star way to heaven 题解 大致尝试了一下并查集,记忆化搜索,最小生成树 最小生成树是正解,跑最小生成树然后找到最大的值 欧几里德距离最小生成树学习 prim楞跑 至于为什么跑最小生成 ...

  2. NOIP模拟测试19「count·dinner·chess」

    反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...

  3. 8.9 NOIP模拟测试15 建设城市(city)+轰炸行动(bomb)+石头剪刀布(rps)

    鉴于T3的惨烈程度,我决定先来颓篇题解. T1 建设城市(city) 挡板法+容斥 m个建设队分成n组,每组必须有一个,先不考虑上限,共有 C(m-1,n-1)种方案. 有i个组是超过k个的,容斥掉 ...

  4. NOIP模拟测试30「return·one·magic」

    magic 题解 首先原式指数肯定会爆$long$ $long$ 首先根据欧拉定理我们可以将原式换成$N^{\sum\limits_{i=1}^{i<=N} [gcd(i,N)==1] C_{G ...

  5. NOIP模拟测试21「折纸·不等式」

    折纸 题解 考试时无限接近正解,然而最终也只是接近而已了 考虑模拟会爆炸,拿手折纸条试一试,很简单 考你动手能力 代码 #include<bits/stdc++.h> using name ...

  6. NOIP模拟测试18「引子·可爱宝贝精灵·相互再归的鹅妈妈」

    待补 引子 题解 大模拟,注意细节 代码1 #include<bits/stdc++.h> using namespace std; int n,m;char a[1005][1005]; ...

  7. NOIP模拟测试10「大佬·辣鸡·模板」

    大佬 显然假期望 我奇思妙想出了一个式子$f[i]=f[i-1]+\sum\limits_{j=1}^{j<=m} C_{k \times j}^{k}\times w[j]$ 然后一想不对得容 ...

  8. NOIP模拟测试38「金·斯诺·赤」

    金 辗转相减见祖宗 高精 #include<bits/stdc++.h> using namespace std; #define A 2000 #define P 1 #define N ...

  9. NOIP模拟测试34「次芝麻·呵呵呵·长寿花」

    次芝麻 题解 大力打表,发现快速幂, 例如初始$5$ $6$,那么第一次就是$5*2\%11=10$,$6*2\%11=1$. 代码 #include<bits/stdc++.h> usi ...

最新文章

  1. intel的linux证书过期,rhce证书过期了可以怎么办
  2. DALL·E才发布两天就被复现?官方论文还没出,大神们就在自制代码和视频了
  3. python怎么读取列表-Python如何获取列表(List)的中位数
  4. Head First C 第八章 静态库与动态库 创建动态库
  5. Tensorflow Day19 Denoising Autoencoder
  6. Scala样例类及密封类
  7. android 1396x750设计图,移动端的适配|切图|标注
  8. java开发模型_java开发模型MVC
  9. 整理一些完全免费开放的API接口
  10. springboot转发http请求_网易后端实习生分享:Springboot异常和错误处理规范
  11. 【java机器学习】支持向量机之拉格朗日乘子法解释
  12. QML笔记-KeyNavigation的使用(2种例子)
  13. 关于计算机人工智能的知识,《计算机科学导论》人工智能基础知识
  14. java反向代理开源_树莓派反向代理方法大全
  15. 投资问题(动态规划)
  16. 排污口漂浮物监测系统 yolov5
  17. CleanMyMac不停要求输入密码进行更改
  18. EXCEL文件(xlsx)的读取与data的写入
  19. 如何做一个基于微信酒店预订小程序系统毕业设计毕设作品
  20. 洛谷 P1477 [NOI2008]假面舞会

热门文章

  1. MacBook/MacOS/Mac OS 查看进程/端口信息的相关命令
  2. datax 持续数据同步_采用DataX实现多表增量数据同步
  3. 远程服务器如何创建分支,git如何远程创建分支
  4. @insert 对象_python中列表插入append(), extend(), insert()
  5. 【WebRTC---进阶篇】(四)mediasoup服务器的布署与使用
  6. Windows内存修改初篇
  7. 编程语言:C语言与Java的细致对比,你知道选谁了吗?
  8. C语言变量定义和赋值
  9. android王者调不了界面,王者荣耀登录界面怎么改?登录界面更改教程[多图]
  10. python删除字符串中指定_python删除字符串中指定字符