解题思路
我太开心了,T1打了两个小时,结果真的A了!!!
其实思路还是挺简单的,就是多方程解三个未知数。先暴搜枚举每个x_i表示什么(A,B,A+C,A+B+C……),就是题目给出的七种,因为每个x_i都不一样所以这里可以剪枝一下。然后把每个x_i作为一个方程的答案,每个方程的样子是: x ∗ A + y ∗ B + z ∗ C = x i x* A+y* B+z* C=x_i x∗A+y∗B+z∗C=xi.
我们要解的是A,B,C,已知系数x,y,z
(因为系数这就是你深搜的东西,如:
x
i
=
A
+
B
x_i=A+B
xi=A+B时,
1
∗
A
+
∗
B
+
0
∗
C
=
x
i
1*A+*B+0*C=x_i
1∗A+∗B+0∗C=xi)
就可以开始高斯消元了,只用枚举三列,因为只用三个未知数,最后得出答案,如果有复数或非整数都r不成立,然后还要判断这组答案是否和之前的重复。(我的去重很暴力,就剪了个数组,存所有的答案,注意存的时候提前排个序)
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
#define ldb long double
using namespace std;
int T,n,ans,a[10],v[10],f[5000010][4],vis[10];
ldb c[10][5];
int b[8][4]={{},{0,1,0,0},{0,0,1,0},{0,0,0,1},{0,1,1,0},{0,1,0,1},{0,0,1,1},{0,1,1,1}};
bool check(){
for(int i=1;i<=n;i++)
{
for(int j=1;j<=3;j++)
c[i][j]=b[v[i]][j];
c[i][4]=a[i];
}
for(int i=1;i<=3;i++)
{
int x=i;
for(int j=i+1;j<=n;j++)
{
if(abs(c[j][i])>abs(c[x][i]))
x=j;
}
if(c[x][i]==0)
return 0;
for(int j=1;j<=4;j++)
swap(c[i][j],c[x][j]);
for(int j=1;j<=n;j++)
{
if(i!=j)
{
ldb tmp=c[j][i]/c[i][i];
for(int t=i;t<=4;t++)
c[j][t]-=c[i][t]*tmp;
}
}
}
int ok=0,w[4];
for(int i=1;i<=3;i++)
{
w[i]=c[i][4]/c[i][i];
if((w[i]*c[i][i]!=c[i][4])||w[i]<=0)
return 0;
}
for(int i=4;i<=n;i++)
if(c[i][4]!=0)
return 0;
sort(w+1,w+3+1);
for(int i=1;i<=ans;i++)
{
ok=0;
for(int j=1;j<=3;j++)
{
if(f[i][j]==w[j])
ok++;
}
if(ok==3)
return 0;
}
for(int i=1;i<=3;i++)
f[ans+1][i]=w[i];
return 1;
}
void dfs(int dep){
if(dep>n)
{
if(check())
ans++;
return;
}
for(int i=1;i<=7;i++)
{
if(!vis[i])
{
vis[i]=1;
v[dep]=i;
dfs(dep+1);
vis[i]=0;
}
}
}
int main(){
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
ans=0;
dfs(1);
printf("%d\n",ans);
}
}