1. 程式人生 > 其它 >[cf1444D]Rectangular Polyline

[cf1444D]Rectangular Polyline

由於兩種線段要交替出現,有解的必要條件即為$h=v$(以下均記為$n$)

進一步的,再假設兩種線段依次對應於向量$(a_{i},0)$和$(0,b_{i})$,根據題意要求向量長度為給定值且和為0,那麼也即有$|a_{i}|=l_{i},|b_{i}|=p_{i}$且$\sum_{i=1}^{n}a_{i}=\sum_{i=1}^{n}b_{i}=0$

使用揹包判定是否存在這樣的$a_{i}$和$b_{i}$,若不存在即無解,若存在則再求出任意一組

(可以證明此時一定有解,以下即為構造)

若$a_{i}$中的負數少於$b_{i}$則將兩者全部取相反數,再將兩者分別從大到小排序(其實只需要保證正數在負數前),最後將$(a_{i},b_{i})$作為一個整體極角排序,並依次選擇$(a_{1},0),(0,b_{1}),(a_{2},0),...,(b_{n},0)$即可

(程式碼實現上通過將兩邊分別合理排序使得其已經極角排序)

不難發現,以此法最終方案一定是形如下圖的形式,即合法

時間複雜度為$o(\frac{nC^{2}}{\omega})$,可以通過

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1005
 4 bitset<N*N>f[N];
 5 int t,n,m,a[N],b[N];
 6 int calc(int *a){
 7     int m=0;
 8     for(int i=1;i<=n;i++)m+=a[i];
 9     if
(m&1)return 0; 10 m>>=1; 11 for(int i=1;i<=n;i++)f[i]=((f[i-1])|(f[i-1]<<a[i])); 12 if (!f[n][m])return 0; 13 for(int i=n;i;i--) 14 if (!f[i-1][m]){ 15 m-=a[i]; 16 a[i]=-a[i]; 17 } 18 return 1; 19 } 20 int main(){ 21 f[0][0
]=1; 22 scanf("%d",&t); 23 while (t--){ 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 26 scanf("%d",&m); 27 for(int i=1;i<=m;i++)scanf("%d",&b[i]); 28 if ((n!=m)||(!calc(a))||(!calc(b))){ 29 printf("No\n"); 30 continue; 31 } 32 int cnt=0; 33 for(int i=1;i<=n;i++)cnt+=(a[i]<0)-(b[i]<0); 34 if (cnt<0){ 35 for(int i=1;i<=n;i++)a[i]=-a[i],b[i]=-b[i]; 36 } 37 sort(a+1,a+n+1),reverse(a+1,a+n+1); 38 sort(b+1,b+n+1),reverse(b+1,b+n+1); 39 for(int i=1;i<=n+1;i++) 40 if ((i>n)||(a[i]<0)){ 41 reverse(b+1,b+i); 42 break; 43 } 44 for(int i=n;i>=0;i--) 45 if ((!i)||(b[i]>0)){ 46 reverse(a+i+1,a+n+1); 47 break; 48 } 49 printf("Yes\n"); 50 for(int i=1,x=0,y=0;i<=n;i++){ 51 x+=a[i],printf("%d %d\n",x,y); 52 y+=b[i],printf("%d %d\n",x,y); 53 } 54 } 55 return 0; 56 }
View Code