城市价值

Description

BB很喜欢玩《文明》,因此它知道很多游戏的攻略。有一个攻略根据城市的N 种资源的数量,对地图上许多位置的城市都计算了一个价值分数并给出了如下公式:
一座城市的价值分数=资源1的数量*资源1的价值+资源2 的数量*资源2的价值+资源3的数量*资源3的价值+……+资 源N 的数量*资源N 的价值。
然而,SS却是首次接触这个游戏。所以它非常好奇每种资源的价值是如何得出的,于是它找了N 座城市,并获得了这N座城市每座城市N 种资源的数量信息。由于数据量实在很大,因此SS把这些数据给了你。它希望你能帮它算出,每种资源的价值是多少,这样它就能够自己计算出其它城市的价值分数了。

Input

输入文件第1 行包含一个整数N,含义如题所述。
第2 行到第N+1 行,每行N+1 个正整数。第i+1 行的第j(j<=N)个整数表示第i 个城市含有资源j的数量,第N+1个整数表示这个城市的价值分数。

Output

输出N行,每行一个整数,第i行的整数表示第i种资源的价值。

Sample Input

1

1 1

Sample Output

1

Hint

数据范围与约定
对于40%的数据,N<=10,每种资源的价值在[0,10^9]之间,资源的数量在[0,128]之间;
对于70%的数据,N<=100;
对于100%的数据,N<=200,每种资源的价值在[0,10^18]之间,资源的数量在[0,10^9]
之间,保证有唯一解,保证答案一定为自然数。

高斯消元的板子,发现会炸long long,取余之后用中国剩余定理确定取值,又发现会爆long long,用慢速乘。

#include<bits/stdc++.h>
using namespace std;
const int Maxn=1005;
#define ll long long
char s[Maxn];
ll x[2][Maxn];
ll n,a[2][Maxn][Maxn];
ll p[2]={1e9+7,1e9+9};
ll ksm(ll a,ll b,ll p){
	ll ans=1,ret=a;
	for(;b;b>>=1){
		if(b&1)(ans*=ret)%=p;
		(ret*=ret)%=p;
	}
	return ans;
}
#define inv(a,p) ksm(a,p-2,p)
void init(){
	scanf("%lld",&n);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			ll num;scanf("%lld",&num);
			for(int k=0;k<2;++k)
				a[k][i][j]=num%p[k];
		}
		scanf("%s",s+1);
		int len=strlen(s+1);
		for(int j=1;j<=len;++j)
			for(int k=0;k<2;++k)
				(((a[k][i][n+1]*=10)%=p[k])+=(s[j]-'0'))%=p[k];
	}
}
void gauss(int t,int x){
	int mx=a[t][x][x],mxp=0;
	for(int i=x+1;i<=n;++i)
		if(a[t][i][x]>mx){mx=a[t][i][x];mxp=i;break;}
	if(mxp)for(int i=x;i<=n+1;++i)swap(a[t][x][i],a[t][mxp][i]);
	ll inv=inv(a[t][x][x],p[t]);
	for(int i=x+1;i<=n;++i){
		ll kd=a[t][i][x]*inv%p[t];
		for(int j=x;j<=n+1;++j)
			(((a[t][i][j]-=kd*a[t][x][j])%=p[t])+=p[t])%=p[t];
	}
}
void gauss(int t){
	for(int i=1;i<n;++i)gauss(t,i);
}
ll mult(ll a,ll b,ll p){
    ll ans=0,ret=a;
    for(;b;b>>=1){
        if(b&1)(ans+=ret)%=p;
        (ret<<=1)%=p;
    }
    return ans; 
}
void encode(int t){
	for(int i=n;i>=1;--i){
		x[t][i]=((a[t][i][n+1]*inv(a[t][i][i],p[t])%p[t])+p[t])%p[t];
		for(int j=n;j>=i;--j)
			(((a[t][i-1][n+1]-=a[t][i-1][j]*x[t][j])%=p[t])+=p[t])%=p[t];
	}
}
ll decode(int idx){
	ll ans=0,P=p[0]*p[1];
	for(int i=0;i<2;++i){
		(ans+=mult(mult(x[i][idx],inv(p[i^1],p[i]),P),p[i^1],P))%=P;
//		(((ans+=x[i][idx]*inv(p[i^1],p[i])%P*p[i^1]%P)%=P)+=P)%=P;
	}
	return (ans%P+P)%P;
}
int main(){
	init();
	gauss(0);
	gauss(1);
	encode(0);
	encode(1);
	for(int i=1;i<=n;++i)
		cout<<decode(i)<<'\n';
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值