jzoj3539. 折射伤害

题目描述

Description
在一个游戏中有n个英雄,初始时每个英雄受到数值为ai的伤害,每个英雄都有一个技能“折射”,即减少自己受到的伤害,并将这部分伤害分摊给其他人。对于每个折射关系,我们用数对(xi,yi,zi)来表示xi将自己受到伤害去掉zi的比例,将这些伤害转移给yi(xi,yi是整数,zi是实数)。

求出经过反复折射后最后每个英雄受到的实际总伤害。

Input
第一行一个正整数:n,表示有n个英雄,第二行n个整数Ai,依次表示每个英雄受到的初始伤害。第三行一个正整数m,表示有m对折射关系。接下来m行,每行三个数xi,yi,zi,表示xi将自己受到伤害去掉zi的比例,将这些伤害转移给yi。

Output
输出n行,第i行表示第i个英雄最后受到的实际总伤害。保留六位小数。

Sample Input
3

1 0 2

3

1 2 0.3000

1 2 0.2000

2 1 0.5000

Sample Output
0.666667

扫描二维码关注公众号,回复: 12794662 查看本文章

0.333333

2.000000

Data Constraint
在这里插入图片描述

20%

全员坑人
根据题意模拟,每次记录本轮能反弹的伤害,然后根据时间大概算一下能跑多少轮

100%

想到了的话就是sb题
设f(x),表示x总共接受+反弹的伤害(即每轮存储在x的可弹的伤害之和)
若有一条边x–>y,比率为z
则f(y)=f(x)*z+y的初始伤害
因为x每收到一点伤害都要反弹,所以y收到的来自x的总伤害就是f(x)*z
高斯消元即可
最后ans[x]=f(x)*(1-∑zi) (zi∈x的出边),即算出x接受的真正伤害

解法好评,但卡精度差评

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
#define E 0.00000001
#define C 1000
using namespace std;

long double a[201][202];
int id[201];
long double ans[201];
long double tot[201];
int n,m,i,j,k,l;
long double s;

void work()
{
    
    
	fo(i,1,n)
	{
    
    
		fo(j,1,n)
		if (abs(a[i][j])>E)
		{
    
    
			if (!id[j])
			{
    
    
				id[j]=i;
				
				s=a[i][j];
				fo(k,j,n+1)
				a[i][k]/=s;
				
				break;
			}
			else
			{
    
    
				s=a[i][j];
				fo(k,j,n+1)
				a[i][k]-=s*a[id[j]][k];
			}
		}
	}
	
	fd(i,n,1)
	{
    
    
		ans[i]=a[id[i]][n+1];
		
		fo(j,1,i-1)
		a[j][n+1]-=ans[i]*a[j][i];
	}
}

int main()
{
    
    
//	freopen("damage6.in","r",stdin);
//	freopen("S8_4_2.in","r",stdin);
	
	scanf("%d",&n);
	fo(i,1,n)
	{
    
    
		scanf("%d",&j);
		
		a[i][i]=1*C;
		a[i][n+1]=j*C*C;
	}
	
	scanf("%d",&m);
	fo(i,1,m)
	{
    
    
		scanf("%d%d%Lf",&j,&k,&s);
		
		a[k][j]-=s*C;
		tot[j]+=s;
	}
	
	work();
	
	fo(i,1,n)
	printf("%0.6Lf\n",ans[i]*(1-tot[i])/C);
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/98475014