题目链接:https://atcoder.jp/contests/agc063/tasks/agc063_c
做法
无解的充分必要条件:
存在 $i,j(i≠j)$ ,使得 $a_i=a_j,b_i≠b_j$ 。
有解时的构造方法:
设 $c_i$ 表示 $a_i$ 在 $a$ 序列里面从大到小排序的位置。
考虑构造一个这样的序列:$b_i+c_i*K$ ,$K$ 表示一个大于所有 $a$ 的数字。
然后最后全部模 $K$ 就行了。
怎么构造这个序列呢?考虑不算次数的情况,那么先把所有数字加个 INF ,然后每次让当前最大的数字变成 $0$,并且再变成 $0$ 之前加上这个数字与前一个变成 $0$ 的数字之间的间隔,然后就做完了。
然后只要精细化的处理一下这个过程,就可以办到恰好 $n$ 次做完这个过程。
时间复杂度:$O(n\log{n})$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
   | #include<bits/stdc++.h> #define N 1100 using namespace std; typedef long long LL; typedef pair<LL,LL> PLL; const LL inf=1e16; LL a[N],b[N];int n; int top,sta[N];LL now,d[N]; PLL c[N];LL maxcost=0; inline bool cmp(int x,int y){return a[x]>a[y];} int main(){     scanf("%d",&n);     for(int i=1;i<=n;i++)scanf("%lld",&a[i]);     for(int i=1;i<=n;i++){scanf("%lld",&b[i]);maxcost=max(maxcost,b[i]+1);}     for(int i=1;i<=n;i++){         bool bk=0;         for(int j=1;j<=n;j++){             if((a[j]==a[i]) && (b[j]!=b[i])){printf("No\n");return 0;}             if(j<i && a[j]==a[i])bk=1;         }         if(!bk)sta[++top]=i;     }     sort(sta+1,sta+top+1,cmp);     for(int i=1;i<top;i++)d[i]=(top-i-1)*maxcost+b[sta[i]];     now=inf;LL nowx=now%maxcost;now+=(b[sta[top]]-nowx+maxcost)%maxcost;now-=a[sta[top]];     c[top].second=maxcost;     printf("Yes\n%d\n",top);     for(int i=top;i>=1;i--){         if(i!=top)c[i].second=now+a[sta[i]];         if(i!=1)c[i].first=d[i-1]-d[i],now-=c[i].first;     }     c[1].first=now;     if(top==1)c[1].first%=c[1].second;     for(int i=1;i<=top;i++)printf("%lld %lld\n",c[i].first,c[i].second);     return 0; }
   |