5-23ACM训练题解(NWERC 2019)
E-Expeditious Cubing Kattis - expeditiouscubing
为了方便,我们将四个数从小到大设为x1,x2,x3,x4,先判断必输和必胜。
必输:t1+t2+t3>t*3
必胜:t2+t3+t4<=t*3
否则解就是t*3-t2-t3。不过要注意精度问题。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <vector> 7 #include <map> 8 #define N 1005 9 using namespace std; 10 int n; 11 long long A[N], K; 12 int main() 13 { 14 n = 4; 15 int l, r; 16 for (int i = 1; i <= n; i++) 17 { 18 scanf("%d.%d", &l, &r); 19 A[i] = l * 100 + r; 20 } 21 sort(A + 1, A + n + 1); 22 scanf("%d.%d", &l, &r); 23 K = l * 100 + r; 24 if (A[1] + A[2] + A[3] > K * 3) 25 { 26 printf("impossible\n"); 27 } 28 else if (A[2] + A[3] + A[4] <= K * 3) 29 { 30 printf("infinite\n"); 31 } 32 else 33 { 34 long long X = K * 3 - A[2] - A[3]; 35 printf("%d.%02d\n", X / 100, X % 100); 36 } 37 return 0; 38 }
F-Firetrucks Are Red Kattis - firetrucksarered
首先,我们要保证能够构建出一个连通性和原图相同且在原图上删边使边数足够少的图。
由于有特征值X的点之间两两有边,因此,我们将它等价转化。设原来x1,x2,x3……都有特征值X。则只将x1,x2 x2,x3 ……之间连边,会发现不会破坏原图的连通性。也就不会因此改变是否有解。
之后跑一个生成树就可以了
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 #include<map> 8 #define N 1000005 9 using namespace std; 10 int n,a[N],B[N][2],m,fa[N]; 11 map<int,int> ma; 12 int A[N],zz1; 13 int zz; 14 struct ro{ 15 int to,next; 16 }road[N]; 17 void build(int x,int y) 18 { 19 zz++; 20 road[zz].to=y; 21 road[zz].next=a[x]; 22 a[x]=zz; 23 } 24 int F[N][3]; 25 int ans[N][3]; 26 int find(int x) 27 { 28 if(fa[x]==x)return x; 29 return fa[x]=find(fa[x]); 30 } 31 int main() 32 { 33 scanf("%d",&n); 34 for(int i=1;i<=n;i++) 35 { 36 int l; 37 scanf("%d",&l); 38 for(int j=1;j<=l;j++) 39 { 40 m++; 41 B[m][0]=i; 42 scanf("%d",&B[m][1]); 43 if(!ma.count(B[m][1])) 44 { 45 ma[B[m][1]]=1; 46 zz1++; 47 A[zz1]=B[m][1]; 48 } 49 } 50 } 51 sort(A+1,A+zz1+1); 52 for(int i=1;i<=zz1;i++) 53 { 54 ma[A[i]]=i; 55 } 56 57 for(int i=1;i<=m;i++) 58 { 59 B[i][1]=ma[B[i][1]]; 60 build(B[i][1],B[i][0]); 61 } 62 int cnt1=0; 63 for(int i=1;i<=zz1;i++) 64 { 65 int la=0; 66 for(int j=a[i];j;j=road[j].next) 67 { 68 int y=road[j].to; 69 if(la) 70 { 71 cnt1++; 72 F[cnt1][0]=la; 73 F[cnt1][1]=y; 74 F[cnt1][2]=i; 75 } 76 la=y; 77 } 78 } 79 for(int i=1;i<=n;i++) fa[i]=i; 80 int cnt=0; 81 for(int i=1;i<=cnt1;i++) 82 { 83 int x=F[i][0],y=F[i][1]; 84 if(find(x)!=find(y)) 85 { 86 cnt++; 87 ans[cnt][0]=x; 88 ans[cnt][1]=y; 89 ans[cnt][2]=A[F[i][2]]; 90 // cout<<x<<' '<<y<<' '<<cnt<<endl; 91 fa[fa[x]]=fa[y]; 92 } 93 } 94 if(cnt!=n-1) 95 { 96 printf("impossible\n"); 97 } 98 else 99 { 100 for(int i=1;i<=cnt;i++) printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]); 101 } 102 return 0; 103 }
I- Inverted Deck Kattis - inverteddeck
我们先将原序列排序,然后找到与原序列第一个不一样的位置x和最后一个不一样的位置y,将x~y颠倒,如果和排序后的序列完全相同则xy为解,否则无解
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define N 1000005 7 using namespace std; 8 int n,A[N],B[N]; 9 int main() 10 { 11 scanf("%d",&n); 12 for(int i=1;i<=n;i++)scanf("%d",&A[i]),B[i]=A[i]; 13 sort(B+1,B+n+1); 14 int st=1,la=1; 15 for(int i=1;i<=n;i++) 16 { 17 if(A[i]!=B[i]) 18 { 19 st=i; 20 break; 21 } 22 } 23 for(int i=n;i;i--) 24 { 25 if(A[i]!=B[i]) 26 { 27 la=i; 28 break; 29 } 30 } 31 for(int i=st;i<=la;i++) 32 { 33 if(i<=la-(i-st)) 34 { 35 swap(A[i],A[la-(i-st)]); 36 } 37 } 38 bool yx=1; 39 for(int i=1;i<=n;i++) 40 { 41 if(A[i]!=B[i]) 42 { 43 yx=0; 44 break; 45 } 46 } 47 if(yx) 48 { 49 printf("%d %d\n",st,la); 50 } 51 else 52 { 53 printf("impossible\n"); 54 } 55 return 0; 56 }
J-Jackdaws and Crows Kattis - jackdawsandcrows
挺好的一道题。
首先我们可以想到的是要在c和r的使用次数中控制一个,然后计算另一个的最小值。
如果我们尝试控制r的使用次数,会发现还是很难计算c的次数,因此我们尝试控制c的使用次数。
不难发现,c的使用次数一定是|Sx|+1或0,而且如果c使用了X次,则所有|Sx|<X的符号都可以任意变换。
一开始我是想利用三分,但是WA 15,应该是因为此题不满足三分的性质。
那么我们就需要去枚举C的使用次数了。
为了方便,我们从小到大依次枚举,那么我们就需要在小于O(log)的时间内算出|Sx|的符号可以随意变换对于答案的影响。
可以发现,在C的使用次数确定的时候X是否应当被删除只取决于他前面第一个符号不可以变换的值。因此我们可以利用链表维护将一个数删去对于答案的影响。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 #include<map> 8 #define N 500005 9 using namespace std; 10 int n,C,R; 11 int A[N],B[N]; 12 int pr[N],fr[N]; 13 map<int,int> st,ma; 14 struct ro{ 15 int to,next; 16 }road[N]; 17 int zz,a[N]; 18 void build(int x,int y) 19 { 20 zz++; 21 road[zz].to=y; 22 road[zz].next=a[x]; 23 a[x]=zz; 24 } 25 int cnt; 26 long long ans; 27 int main() 28 { 29 // freopen("test.in","r",stdin); 30 // freopen("2.out","w",stdout); 31 scanf("%d%d%d",&n,&C,&R); 32 for(int i=1;i<=n;i++){ 33 scanf("%d",&A[i]); 34 if(!ma[abs(A[i])]) 35 { 36 ma[abs(A[i])]=1; 37 cnt++; 38 B[cnt]=abs(A[i]); 39 } 40 } 41 sort(B+1,B+cnt+1); 42 for(int i=1;i<=cnt;i++) ma[B[i]]=i; 43 int La=0; 44 for(int i=n;i;i--) 45 { 46 build(ma[abs(A[i])],i); 47 } 48 long long sum=0; 49 for(int i=1;i<=n;i++) 50 { 51 if(A[i]==0) 52 { 53 sum+=R; 54 continue; 55 } 56 if(La!=0) 57 { 58 if(1ll*A[La]*A[i]>0) sum+=R; 59 // else if(1ll*A[La]*A[i]<0&&((i-La+1)&1)) sum+=R; 60 } 61 La=i; 62 // cout<<i<<' '<<A[i]<<' '<<sum<<endl; 63 } 64 ans=sum; 65 sum=C; 66 La=0; 67 68 for(int i=1;i<=n;i++) 69 { 70 if(A[i]) 71 { 72 fr[La]=i; 73 pr[i]=La; 74 if(La) 75 { 76 if(1ll*A[i]*A[La]>0&&((i-La)&1)) 77 { 78 sum+=R; 79 } 80 else if(1ll*A[i]*A[La]<0&&((i-La+1)&1)) 81 { 82 sum+=R; 83 } 84 } 85 La=i; 86 } 87 } 88 ans=min(ans,sum); 89 pr[n+1]=La; 90 fr[La]=n+1; 91 for(int i=1;i<=cnt;i++) 92 { 93 if(B[i]==0) continue; 94 sum+=1ll*C*(B[i]-B[i-1]); 95 for(int j=a[i];j;j=road[j].next) 96 { 97 int y=road[j].to; 98 int f=fr[y],p=pr[y]; 99 if(p!=0&&f!=n+1) 100 { 101 bool yx1=1,yx2=1; 102 if(1ll*A[f]*A[y]>0&&((f-y)&1)) yx1=0; 103 if(1ll*A[p]*A[y]>0&&((y-p)&1)) yx2=0; 104 if(1ll*A[f]*A[y]<0&&((f-y+1)&1)) yx1=0; 105 if(1ll*A[p]*A[y]<0&&((y-p+1)&1)) yx2=0; 106 if((!yx1)&&(!yx2)) 107 { 108 sum-=2ll*R; 109 pr[f]=pr[y]; 110 fr[p]=fr[y]; 111 if(1ll*A[f]*A[p]>0&&((f-p)&1)) sum+=R; 112 if(1ll*A[f]*A[p]<0&&((f-p+1)&1)) sum+=R; 113 } 114 else 115 { 116 pr[f]=pr[y]; 117 fr[p]=fr[y]; 118 } 119 } 120 else if(p==0&&f!=n+1) 121 { 122 bool yx1=1; 123 if(1ll*A[f]*A[y]>0&&((f-y)&1)) yx1=0; 124 if(1ll*A[f]*A[y]<0&&((f-y+1)&1)) yx1=0; 125 if(!yx1) 126 { 127 sum-=R; 128 129 } 130 pr[f]=pr[y]; 131 fr[p]=fr[y]; 132 } 133 else if(p!=0&&f==n+1) 134 { 135 bool yx1=1; 136 if(1ll*A[p]*A[y]>0&&((y-p)&1)) yx1=0; 137 if(1ll*A[p]*A[y]<0&&((y-p+1)&1)) yx1=0; 138 if(!yx1) 139 { 140 sum-=R; 141 } 142 pr[f]=pr[y]; 143 fr[p]=fr[y]; 144 } 145 else 146 { 147 pr[f]=pr[y]; 148 fr[p]=fr[y]; 149 } 150 // cout<<B[i]<<' '<<y<<' '<<sum<<' '<<p<<' '<<f<<endl; 151 } 152 ans=min(ans,sum); 153 } 154 printf("%lld\n",ans); 155 return 0; 156 }