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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code
posted @ 2020-05-27 10:39  Hzoi_joker  阅读(362)  评论(0编辑  收藏  举报