“景驰科技杯”2018年华南理工大学程序设计竞赛 H-对称与反对称(逆元)
题目链接:点击打开链接
题目描述:
题目分析:
对于这个题目因为根据题目所给的条件可知:
Aij=Bij+Cij(1)
Aji=Bji+Cji(2)
(1)-(2)可得
Aij-Aji=Bij-Bji+(Cij-Cji); 而又有 Bij=Bji Cij=-Cji
因此得到式子
2*Cij=Aij-Aji
Cij=(Aij-Aji)/2
故因此只需要通过该公式进行枚举即可
但是仍然要注意因为题目提示所有运算都应该在满足M的意义下进行,因此Cij不能出现非整数的情况,这是我们就可以通过逆元来求出Cij的值。
但是需要尤其注意的是,因为题目中所给的模数M是奇数,但不一定是质数,因此以费马小定理为理论依据的快速幂求逆元的方法是不一定成立的!!!(比赛过程中忘了这个细节而从头WA到尾/(ㄒoㄒ)/~~);
因此在该题只能通过拓展欧几里得或者一种构造函数的思想去解决。
#include <bits/stdc++.h>
#define maxn 1005
using namespace std;
typedef long long ll;
//StartCoding:
ll a[maxn][maxn];
ll c[maxn][maxn];
void ex_gcd(ll a,ll b,ll &x,ll &y,ll&d){
if(!b) d=a,x=1,y=0;
else{
ex_gcd(b,a%b,y,x,d);
y-=x*(a/b);
}
}
ll inv(int t,int p){
ll d,x,y;
ex_gcd(t,p,x,y,d);
return d==1?(x%p+p)%p:-1;//扩展gcd是可行的
}
ll inv2(ll t,ll p){
return t==1?1:(p-p/t)*inv2(p%t,p)%p;//这一种构造逆元的方法也是可行的
}
ll quick_power(ll a,ll n,ll mod){
if(n==0) return 1;
ll res=quick_power(a*a,n>>1,mod);
if(n&1) res=res*a%mod;
return res;
}
ll inv3(ll t,ll p){
return quick_power(t,p-2,p);//快速幂是不行哒!!!
}
int main()
{
ll n,m;
while(cin>>n>>m){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
c[i][j]=((a[i][j]-a[j][i])*inv2(2,m))%m;//一个数除以2等于乘上2的逆元
while(c[i][j]<0){//因为要保证在m下有意义,因此最后的结果需要是正数
c[i][j]+=m;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(j==1) cout<<c[i][j];
else cout<<" "<<c[i][j];
}
cout<<endl;
}
}
return 0;
}