Description
Input
Output
Sample Input
6 6 2 2 1
5 3 5 1 4
Sample Output
1 5 2
5 7 1
5 2 4
7 3 3
1 4 2
1 6 1
题解:如果我们已经确定了点1到点n的距离,那么我们就可以将1到n这条路拿出来,然后其他点都想挂链一样挂到这条路径上即可。即:
如果1到n的长度是m,我们将所有d1-dn相同的点放到一起,那么对于每组d1-dn相同的点,要么|d1-dn|=m,要么d1+dn的最小值=m。所以用数组记录一下即可。
输出方案的时候将所有d1+dn=m的点排个序即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N=500010; const int M=1000010; int n,m,tot,cnt; int d1[N],d2[N],s1[M<<1],s2[M<<1],p[M],mn[M<<1],pa[N],pb[N],pc[N]; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd() { int ret=0,f=1; char gc=nc(); while(!isdigit(gc)) {if(gc=='-') f=-f; gc=nc();} while(isdigit(gc)) ret=ret*10+(gc^'0'),gc=nc(); return ret*f; } inline int abs(int x) {return x>0?x:-x;} inline bool check(int x) { if(((x>=M||x<=-M)?0:(s1[M+x]+s1[M-x]))+s2[x]==n-2) { m=x; return 1; } return 0; } inline void add(int a,int b,int c) { pa[++cnt]=a,pb[cnt]=b,pc[cnt]=c; } int main() { n=rd(); if(n==2) { printf("TAK\n1 2 1"); return 0; } register int i,last; for(i=2;i<n;i++) d1[i]=rd(); for(i=2;i<n;i++) { d2[i]=rd(); int &t=mn[d2[i]-d1[i]+M]; if(!t||d1[t]+d2[t]>d1[i]+d2[i]) t=i; s1[d2[i]-d1[i]+M]++; } for(i=2;i<n;i++) if(i==mn[d2[i]-d1[i]+M]) s2[d1[i]+d2[i]]+=s1[d2[i]-d1[i]+M]; for(i=2;i<n;i++) if(check(abs(d2[i]-d1[i]))||check(d1[i]+d2[i])) break; if(!m) { puts("NIE"); return 0; } for(i=2;i<n;i++) { if(d2[i]-d1[i]==m) add(i,1,d1[i]); else if(d1[i]-d2[i]==m) add(i,n,d2[i]); else if(i==mn[d2[i]-d1[i]+M]) p[d1[i]]=i; else { int t=mn[d2[i]-d1[i]+M]; add(i,t,(d1[i]+d2[i]-d1[t]-d2[t])>>1); } } p[m]=n,d1[n]=m; for(last=i=1;i<=m;i++) if(p[i]) add(last,p[i],d1[p[i]]-d1[last]),last=p[i]; for(i=1;i<n;i++) if(pc[i]<=0) { puts("NIE"); return 0; } puts("TAK"); for(i=1;i<n;i++) printf("%d %d %d\n",pa[i],pb[i],pc[i]); return 0; }//6 2 5 4 8 4 1 6 4
| 欢迎来原网站坐坐! >原文链接<