火山喷发

火山喷发对所有附近的生物具有毁灭性的影响。在本题中,我们希望用数值来模拟这一过程。

在环境里有 n 个生物分别具有 A​1​​,A​2​​,⋯,A​n​​点生命值,一次火山喷发总计 MM 轮,每轮造成 11 点伤害,等概率地分给所有存活的生物,即如果目前有 K 个活着的生物,每个生物受到这点伤害的概率是 1/K​​。如果一个生物的生命值减为 0,它会立即死去,此后都不会再占用受到伤害的概率。如果没有生物存活,那么将没有生物会受到伤害。

现在你的任务是,给定 n,M 和全部生物的生命值,问每个生物火山喷发后依然存活的概率。

输入格式

第一行两个正整数 n 和 M。

第二行 nn 个正整数 A_1,...,A_n。

输出格式

n 行,第 i 行一个数表示第 i 个生物存活下来的概率,保留小数点后六位。

数据范围与约定

对于 10% 的数据 N=1。

对于 30% 的数据 N=2。

对于全部数据 N≤4,M≤120,A​i​​≤50。

样例输入1

1 2
1

样例输出1

0.000000

样例输入2

3 15
2 12 2

样例输出2

0.001684
0.996632
0.001684

信息传递

样例输入

3 2
0 1 0
0 1 4
1 0 2
4 2 0

样例输出

0.400000
0.350000
0.250000

任性的国王

样例输入

4 14
2 3 4 3 1 1 1 5 4 7
1 1 2
1 2 3
1 1 3
1 2 4
2 1 5
1 1 4
4 2 1
1 1 3
1 2 3
1 2 4
3 3 100
1 3 4
1 2 4
1 1 4

样例输出

6
8
10
13
17
9
5
10
15
16
20

T1:

普通dp(太暴力啦)

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#define MAXN 5
using namespace std;
namespace solve1{
int a[MAXN];
void solve(int n,int m){
scanf("%d",&a[]);
double ans;
if(a[]<=m){
ans=;
printf("%.6f\n",ans);
}
else{
ans=;
printf("%.6f\n",ans);
}
}
}
namespace solve2{
int a[MAXN];
double f[][][];
void solve(int n,int m){
scanf("%d%d",&a[],&a[]);
f[][a[]][a[]]=;
for(int k=;k<=m;k++){
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
double t;
if(j){
t=0.5;
}
else{
t=;
}
if(i<)f[k][i][j]+=f[k-][i+][j]*t;
if(i){
t=0.5;
}
else{
t=;
}
if(j<)f[k][i][j]+=f[k-][i][j+]*t;
}
}
}
double ans1=,ans2=;
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
ans1+=f[m][i][j];
}
}
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
ans2+=f[m][i][j];
}
}
printf("%.6f\n%.6f\n",ans1,ans2);
}
}
namespace solve3{
int a[MAXN];
double f[][][][];
void solve(int n,int m){
scanf("%d%d%d",&a[],&a[],&a[]);
f[][a[]][a[]][a[]]=;
for(int k=;k<=m;k++){
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
double t=;
double cnt=;
if(!j) cnt=cnt-;
if(!p) cnt=cnt-;
t=t/cnt;
if(i<)f[k][i][j][p]+=f[k-][i+][j][p]*t;
t=;
cnt=;
if(!i) cnt=cnt-;
if(!p) cnt=cnt-;
t=t/cnt;
if(j<)f[k][i][j][p]+=f[k-][i][j+][p]*t;
t=;
cnt=;
if(!i) cnt=cnt-;
if(!j) cnt=cnt-;
t=t/cnt;
if(p<)f[k][i][j][p]+=f[k-][i][j][p+]*t;
}
}
}
}
double ans1=,ans2=,ans3=;
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
ans1+=f[m][i][j][p];
}
}
}
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
ans2+=f[m][i][j][p];
}
}
}
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
ans3+=f[m][i][j][p];
}
}
}
printf("%.6f\n%.6f\n%.6f\n",ans1,ans2,ans3);
}
}
namespace solve4{
int a[MAXN];
double f[][][][];
void solve(int n,int m){
scanf("%d%d%d%d",&a[],&a[],&a[],&a[]);
f[][a[]][a[]][a[]]=;
for(int k=;k<=m;k++){
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
int q=a[]-(k-(a[]-i+a[]-j+a[]-p));
if(q<) continue;
double t=;
double cnt=;
if(!j) cnt=cnt-;
if(!p) cnt=cnt-;
if(!q) cnt=cnt-;
t=t/cnt;
if(i<)f[k][i][j][p]+=f[k-][i+][j][p]*t; t=;
cnt=;
if(!i) cnt=cnt-;
if(!p) cnt=cnt-;
if(!q) cnt=cnt-;
t=t/cnt;
if(j<)f[k][i][j][p]+=f[k-][i][j+][p]*t; t=;
cnt=;
if(!i) cnt=cnt-;
if(!j) cnt=cnt-;
if(!q) cnt=cnt-;
t=t/cnt;
if(p<)f[k][i][j][p]+=f[k-][i][j][p+]*t; t=;
cnt=;
if(!i) cnt=cnt-;
if(!j) cnt=cnt-;
if(!p) cnt=cnt-;
t=t/cnt;
f[k][i][j][p]+=f[k-][i][j][p]*t;
}
}
}
}
double ans1=,ans2=,ans3=,ans4=;
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
ans1+=f[m][i][j][p];
}
}
}
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
ans2+=f[m][i][j][p];
}
}
}
for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
ans3+=f[m][i][j][p];
}
}
} for(int i=;i<=a[];i++){
for(int j=;j<=a[];j++){
for(int p=;p<=a[];p++){
int q=a[]-(m-(a[]-i+a[]-j+a[]-p));
if(q){
ans4+=f[m][i][j][p];
}
}
}
}
printf("%.6f\n%.6f\n%.6f\n%.6f\n",ans1,ans2,ans3,ans4);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
if(==n){
solve1::solve(n,m);
}
else if(==n){
solve2::solve(n,m);
}
else if(==n){
solve3::solve(n,m);
}
else{
solve4::solve(n,m);
}
return ;
}

Code1-1

其实这题可用bfs转移状态,因为按照总伤害,前面的不会对后面的产生影响,所以开始轮到队头元素时,一定是最优的

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#define MAXN 52
using namespace std;
struct Node{
int a[];
Node(int p1=,int p2=,int p3=,int p4=){
a[]=p1,a[]=p2,a[]=p3,a[]=p4;
}
};
queue<Node> q;
double f[][][][];
bool b[][][][];
int n,m; int main()
{
int a[]={},c[]={};
scanf("%d%d",&n,&m);
for(int i=;i<n;i++){
scanf("%d",&c[i]);
}
f[c[]][c[]][c[]][c[]]=;
q.push(Node(c[],c[],c[],c[]));
while(!q.empty()){
memcpy(a,q.front().a,sizeof(a));
int sum=;
for(int i=;i<;i++){
sum+=(c[i]-a[i]);
}
if(sum>m){
break;
}
q.pop();
int cnt=;
for(int i=;i<;i++){
if(a[i]){
cnt++;
}
}
double t=/(double)cnt;
if(a[]){
f[a[]-][a[]][a[]][a[]]+=f[a[]][a[]][a[]][a[]]*t;
if(!b[a[]-][a[]][a[]][a[]]){
b[a[]-][a[]][a[]][a[]]=;
q.push(Node(a[]-,a[],a[],a[]));
}
}
if(a[]){
f[a[]][a[]-][a[]][a[]]+=f[a[]][a[]][a[]][a[]]*t;
if(!b[a[]][a[]-][a[]][a[]]){
b[a[]][a[]-][a[]][a[]]=;
q.push(Node(a[],a[]-,a[],a[]));
}
}
if(a[]){
f[a[]][a[]][a[]-][a[]]+=f[a[]][a[]][a[]][a[]]*t;
if(!b[a[]][a[]][a[]-][a[]]){
b[a[]][a[]][a[]-][a[]]=;
q.push(Node(a[],a[],a[]-,a[]));
}
}
if(a[]){
f[a[]][a[]][a[]][a[]-]+=f[a[]][a[]][a[]][a[]]*t;
if(!b[a[]][a[]][a[]][a[]-]){
b[a[]][a[]][a[]][a[]-]=;
q.push(Node(a[],a[],a[],a[]-));
}
}
}
double ans[];
if(n>=){
ans[]=;
for(int i=;i<=c[];i++){
for(int j=;j<=c[];j++){
for(int k=;k<=c[];k++){
for(int l=;l<=c[];l++){
if(c[]-i+c[]-j+c[]-k+c[]-l==m)
ans[]+=f[i][j][k][l];
}
}
}
}
}
if(n>=){
ans[]=;
for(int i=;i<=c[];i++){
for(int j=;j<=c[];j++){
for(int k=;k<=c[];k++){
for(int l=;l<=c[];l++){
if(c[]-i+c[]-j+c[]-k+c[]-l==m)
ans[]+=f[i][j][k][l];
}
}
}
}
}
if(n>=){
ans[]=;
for(int i=;i<=c[];i++){
for(int j=;j<=c[];j++){
for(int k=;k<=c[];k++){
for(int l=;l<=c[];l++){
if(c[]-i+c[]-j+c[]-k+c[]-l==m)
ans[]+=f[i][j][k][l];
}
}
}
}
}
if(n>=){
ans[]=;
for(int i=;i<=c[];i++){
for(int j=;j<=c[];j++){
for(int k=;k<=c[];k++){
for(int l=;l<=c[];l++){
if(c[]-i+c[]-j+c[]-k+c[]-l==m)
ans[]+=f[i][j][k][l];
}
}
}
}
}
for(int i=;i<n;i++){
printf("%.6f\n",ans[i]);
}
return ;
}

Code1-2


T2:

矩阵快速幂

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 205
using namespace std;
int n,T;
int d[MAXN][MAXN];
int sum[MAXN];
struct Mat{
double a[MAXN][MAXN];
Mat operator *= (const Mat &B){
Mat C;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
C.a[i][j]=;
for(int k=;k<=n;k++){
C.a[i][j]+=a[i][k]*B.a[k][j];
}
}
}
memcpy(a,C.a,sizeof(a));
return *this;
}
};
void Floyed(){
for(int k=;k<=n;k++){
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
for(int i=;i<=n;i++){
sum[i]=;
for(int j=;j<=n;j++){
sum[i]+=d[i][j];
}
}
}
int main()
{
double a[MAXN];
scanf("%d%d",&n,&T);
for(int i=;i<=n;i++){
scanf("%lf",&a[i]);
}
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
scanf("%d",&d[i][j]);
}
}
Floyed();
Mat A;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
A.a[i][j]=(double)d[i][j]/(double)sum[j];
}
}
Mat B;
memcpy(B.a,A.a,sizeof(B.a));
T--;
while(T){
if(T&){
B*=A;
}
A*=A;
T>>=;
}
for(int i=;i<=n;i++){
double ans=;
for(int j=;j<=n;j++){
ans+=a[j]*B.a[i][j];
}
printf("%.6f\n",ans);
}
return ;
}

Code2


T3:

这题巧妙地把线段树和dp的思想结合在了一起,同时还用到了最小生成树

首先我们用f[k][i][j]表示线段树中节点k所对应区间的值,同时i表示左端的竖边是否选,j表示右端的竖边是否选

那么可以得到方程:

f[k][i][j]=min{ f[k<<1][i][1]+f[k<<1|1][1][j]-cot[mid],  f[k<<1][i][1]+f[k<<1|1][0][j]-cot[mid],   f[k<<1][i][0]+f[k<<1|1][1][j]-cot[mid] }

其中cot[mid]表示中间的竖边

证明如下:

(1)如果最小生成树中包含竖边mid

那么左区间和右区间内包含mid的最小生成树合并一定可以得到最优解

(2)如果最小生成树不包含竖边mid

那么由于图是连通的,那么一定存在一条竖边,它要么位于左区间,要么位于右区间(要么两边都有)

就上图来说,如果它位于右区间,那么由于最小生成树一共一定包含9条边,然后左区间包含5-1条边,右区间包含5条边
我们强制左边加上竖边mid,即f[k<<1][i][1],然后减去cot[mid],这样左边一定只会包含左区间的最小生成树的边数-1
这样另一条边就让给了右区间,所以直接是f[k<<1|1][0][j],这样就得到了一定存在一条竖边竖边位于右区间的情况
从效果的角度来看,我们用f[k<<1|1][0][i]的方式使得右区间强制形成一条竖边,然后由于右区间的连通性,
导致左区间处理时相当于已经有了mid这条边,所以左区间是f[k<<1][i][1],然后减去cot[mid]的代价
左区间的话就是f[k<<1][i][0]+f[k<<1|1][1][j]-cot[mid]
 
至此,已经囊括了所有的情况
 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 100005
#define INF 1000000000
using namespace std;
int a[MAXN];
int f[MAXN*][][];
int n;
int up[MAXN],down[MAXN],cot[MAXN];
int read(){
int x=;char ch=getchar();
while(ch<''||ch>''){ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x;
}
void pushup(int k,int c){
int lc=(k<<),rc=(k<<|);
for(int i=;i<;i++){
for(int j=;j<;j++){
int t=INF;
t=min(t,f[lc][i][]+f[rc][][j]-c);
t=min(t,f[lc][i][]+f[rc][][j]-c);
t=min(t,f[lc][i][]+f[rc][][j]-c);
f[k][i][j]=t;
}
}
}
void build(int k,int L,int R){
if(L+==R){
f[k][][]=INF;
f[k][][]=up[L]+down[L]+cot[L+];
f[k][][]=up[L]+down[L]+cot[L];
f[k][][]=min(up[L],down[L])+cot[L]+cot[L+];
return ;
}
build(k<<,L,(L+R)>>);
build(k<<|,(L+R)>>,R);
pushup(k,cot[(L+R)>>]);
}
void ask(int a,int b,int k,int L,int R,int &q00,int &q01,int &q10,int &q11){
if(a<=L&&R<=b){
q00=f[k][][];
q01=f[k][][];
q10=f[k][][];
q11=f[k][][];
return;
}
else{
int mid=((L+R)>>);
if(b<=mid){
ask(a,b,k<<,L,mid,q00,q01,q10,q11);
return;
}
if(a>=mid){
ask(a,b,k<<|,mid,R,q00,q01,q10,q11);
return;
}
int c=cot[mid];
int p00,p01,p10,p11,l00,l01,l10,l11;
ask(a,b,k<<,L,mid,p00,p01,p10,p11);
ask(a,b,k<<|,mid,R,l00,l01,l10,l11); int t=INF;
t=min(t,p01+l10-c);
t=min(t,p01+l00-c);
t=min(t,p00+l10-c);
q00=t; t=INF;
t=min(t,p01+l11-c);
t=min(t,p01+l01-c);
t=min(t,p00+l11-c);
q01=t; t=INF;
t=min(t,p11+l10-c);
t=min(t,p11+l00-c);
t=min(t,p10+l10-c);
q10=t; t=INF;
t=min(t,p11+l11-c);
t=min(t,p11+l01-c);
t=min(t,p10+l11-c);
q11=t;
}
}
void update(int a,int k,int L,int R,int x,int K){
if(L+==R){
if(==K){
up[a]=x;
}
else if(==K){
down[a]=x;
}
else{
cot[a]=x;
}
f[k][][]=INF;
f[k][][]=cot[L]+up[L]+down[L];
f[k][][]=cot[L+]+up[L]+down[L];
f[k][][]=cot[L]+cot[L+]+min(up[L],down[L]);
return;
}
int mid=((L+R)>>);
if(mid>=a){
update(a,k<<,L,mid,x,K);
}
if(mid<=a){
update(a,k<<|,mid,R,x,K);
}
pushup(k,cot[mid]);
}
int main()
{
//freopen("data.in","r",stdin);
n=read();
int T=read();
for(int i=;i<n;i++){
up[i]=read();
}
for(int i=;i<n;i++){
down[i]=read();
}
for(int i=;i<=n;i++){
cot[i]=read();
}
build(,,n+);
for(int i=;i<=T;i++){
int K=read(),S=read(),T=read();
if(==K){
if(S==T){
printf("%d\n",cot[S]);
}
else{
int q00,q01,q10,q11;
ask(S,T,,,n+,q00,q01,q10,q11);
printf("%d\n",min(min(q00,q01),min(q10,q11)));
}
}
else{
update(S,,,n+,T,K);
}
}
return ;
}

Code3

计蒜客NOIP2017提高组模拟赛(三)day1的更多相关文章

  1. 计蒜客NOIP2017提高组模拟赛(四)day1

    T1:小X的质数 小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小 X 认为,质数是一切自然数起源的地方. 在小 X 的认知里,质数是除了本身和 1 以外,没有其他因数的 ...

  2. 计蒜客NOIP2017提高组模拟赛(五)day1-展览

    传送门 发现这题选或不选对状态的优劣程度不会产生影响,如果已经确定了两个数a和b,那么最优的首项和公比也都是唯一确定的, 与对于后面的数x,加进去也好不加进去也好,首项和公比依旧是原来的 于是我们用尺 ...

  3. 计蒜客NOIP2017提高组模拟赛(五)day1-机智的 AmyZhi

    传送门 很水的题目啦QAQ #include<cstdio> #include<cstdlib> #include<algorithm> #include<c ...

  4. 计蒜客NOIP2017提高组模拟赛(五)day2-蚂蚁搬家

    传送门 这题可以用线段树来维护 #include<cstdio> #include<cstdlib> #include<algorithm> #include< ...

  5. 计蒜客NOIP2017提高组模拟赛(五)day2-成绩统计

    传送门 用hash,因为map的复杂度可能在这题中因为多一个log卡掉,但是hash不会 可能因为这个生成的随机数有循环的情况,不是完全均匀的 而且这题hash表的长度也可以开的很大 #include ...

  6. 计蒜客NOIP2017提高组模拟赛(三)day2-数三角形

    传送门 这题有点坑啊 设A为两边颜色不同的角,B为两边颜色相同的角 那么考虑三种三角形:异色,同色,其他 对于任何一个异色三角形,一定会有三个颜色不同的角, 对于任何一个同色三角形,一定会有零个颜色不 ...

  7. 计蒜客NOIP2017提高组模拟赛(三)day2-直线的交点

    传送门 简单几何+逆序对 发现当两条直线甲乙与平板的交点在上面甲在较左的位置,那么下面甲在较右的位置就可以相交 然后把上面的位置排下序,下面离散化+树状数组即可 #include<cstdio& ...

  8. 计蒜客NOIP2017提高组模拟赛(三)day2-小区划分

    传送门 dp,注意边界 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cst ...

  9. 计蒜客 NOIP 提高组模拟竞赛第一试 补记

    计蒜客 NOIP 提高组模拟竞赛第一试 补记 A. 广场车神 题目大意: 一个\(n\times m(n,m\le2000)\)的网格,初始时位于左下角的\((1,1)\)处,终点在右上角的\((n, ...

随机推荐

  1. MySQL 操作详解

    MySQL 操作详解 一.实验简介 本节实验中学习并实践 MySQL 上创建数据库.创建表.查找信息等详细的语法及参数使用方法. 二.创建并使用数据库 1. 创建并选择数据库 使用SHOW语句找出服务 ...

  2. selenium 爬虫

    from selenium import webdriver import time driver = webdriver.PhantomJS(executable_path="D:/pha ...

  3. python 之反射

    通过字符串的形式导入模块 通过字符串的形式,去模块中寻找制定的函数,并执行getattr(模块名,函数名,默认值) 通过字符串的形式,去模块中设置东西setattr(模块名,函数名/变量名,lambd ...

  4. Scrum 冲刺 第七日

    Scrum 冲刺 第七日 站立式会议 燃尽图 今日任务安排 项目发布说明 站立式会议 返回目录 燃尽图 返回目录 今日任务安排 返回目录 项目发布说明 本版本的新功能 不只是简单打地鼠,还有一些不能打 ...

  5. AWS EMR上搭建HBase环境

    0. 概述 AWS的EMR服务为客户提供的托管 Hadoop 框架可以让您轻松.快 速.经济高效地在多个动态可扩展的 Amazon EC2 实例之间分发和处理 大量数据.您还可以运行其他常用的分发框架 ...

  6. 怎么去理解JAVA中类与对象的关系

    首先要明确,在现实生活中,每一个物体都有自己的基本特征,专业一点也可以说成是属性有些甚至还有一定的行为.例如 汽车的特征:有车门.有轮胎.颜色各一等等,行为:有行驶,开车门,开车灯,等等.有这些属性和 ...

  7. Hibernate之深入持久化对象

    Hibernate是一个彻底的O/R Mapping 框架.之所以说彻底,是因为相对于其他的 框架 ,如Spring JDBC,iBatis 需要手动的管理SQL语句,Hibernate采用了完全 面 ...

  8. Vue2学习小记-给Vue2路由导航钩子和axios拦截器做个封装

    1.写在前面 最近在学习Vue2,遇到有些页面请求数据需要用户登录权限.服务器响应不符预期的问题,但是总不能每个页面都做单独处理吧,于是想到axios提供了拦截器这个好东西,再于是就出现了本文. 2. ...

  9. redis入门(15)redis的数据备份和恢复

    redis入门(15)redis的数据备份和恢复

  10. PyMySQL模块的使用

    PyMySQL介绍 PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,Python2系列中则使用mysqldb.Django中也可以使用PyMySQL连接MySQL数据库. ...