题目背景Background
由于模拟赛的良心,相信大家都已经过了t2,于是放这道t3 给大家放松一下
题目描述Description
qiancl 得到了一个长度为n 的序列ai ,他用这个序列构出了一个大小为n*n 的矩阵
,构造方
法为:
,比如
测试数据对应数据范围
其中12个测试点 1<=k,a,b<=105
其中6个测试点 233<=k<=250,且1<=a,b<=108
剩下32个测试点 1<=k,a,b<=1018
然而qiancl 丢失了原本的序列i a ,而且矩阵里的每个数都被打乱了,请你还原原来的序列i a
输入描述(countdown.in) Input Description
第一行一个整数n,接下来一行n*n 个数表示矩阵里的每个数,随机排列
输出描述(countdown.out) Output Description
一行n 个整数从小到大排列表示还原出的序列
样例输入Sample Input
4
2 1 2 3 4 3 2 6 1 1 2 2 1 2 3 2
样例输出Sample Output
2 3 4 6
数据范围及提示Data Size & Hint
对于20%的数据,n<=3
对于另20%的数据,n<=6, ij g <=10
对于100%的数据,n<=400,1<= ij g <=100w
发动大眼观察法,发现ans一定在给出序列中,再观察,最大的6一定在ans中,4也在ans中
由此猜想:ans在最大的几个数中,对于已经找出的ans,我们需要减去它们的gcd,发现正好
然后就没了
#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=405;
int n,cnt;
int a[N*N],ans[N],vis[N*N];
map<int,int>mp;
int gcd(int x,int y) {return !y?x:gcd(y,x%y);}
int main() {
freopen("countdown.in","r",stdin);
freopen("countdown.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n*n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n*n+1);
for (int i=1;i<=n*n;i++)
if (a[i]!=a[i-1]) mp[a[i]]=i;
for (int i=n*n;i>=1;i--) {
if (vis[i]) continue;
ans[++cnt]=a[i];
for (int j=1;j<cnt;j++) {
int gd=gcd(ans[j],ans[cnt]);
int v=mp[gd];
vis[v]=1;vis[v+1]=1;mp[gd]=v+2;
}
}
for (int i=n;i>=1;i--)
printf("%d ",ans[i]);
}
帮同学写了桶排版,简单些
#include <cstdio>
#include <algorithm>
using namespace std;
int gcd(int x,int y) {return !y?x:gcd(y,x%y);}
int n,mx,cnt;
int a[1000007],ans[407];
int main() {
freopen("countdown.in","r",stdin);
freopen("countdown.out","w",stdout);
scanf("%d",&n);
for (int i=1,w;i<=n*n;i++) {
scanf("%d",&w);
a[w]++;
mx=max(w,mx);
}
for (int i=mx;i>=1;i--) {
while(a[i]) {
ans[++cnt]=i;
a[i]--;
for (int j=1;j<cnt;j++)
a[gcd(ans[j],i)]-=2;
}
}
for (int i=cnt;i>=1;i--)
printf("%d ",ans[i]);
}