atcoder beginer 348 (abc348) D E F 题解

 

E

非常经典的树上操作(树上DP)。父节点到某个子节点,值是如何变化的。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <cstdbool>
 6 #include <string>
 7 #include <algorithm>
 8 #include <iostream>
 9 #include <sstream>
10 #include <ctime>
11 #include <stack>
12 #include <vector>
13 #include <queue>
14 #include <set>
15 #include <map>
16 #include <array>
17 using namespace std;
18 #define LL long long
19 #define ULL unsigned long long
20 
21 const LL mod_1=1e9+7;
22 const LL mod_2=998244353;
23 
24 const double eps_1=1e-5;
25 const double eps_2=1e-10;
26 
27 const int maxn=1e5+10;
28 
29 vector<LL> adj[maxn], child[maxn];
30 LL n, c[maxn], fa[maxn], high[maxn] , value[maxn], st[maxn], result=5e18;
31 bool vis[maxn];
32 
33 void find_child(int d)
34 {
35     vis[d]=1;
36     st[d] = c[d];
37     for (int chi:adj[d])
38         if (!vis[chi])
39         {
40             fa[chi]=d;
41             child[d].push_back(chi);
42             high[chi]=high[d]+1;
43 
44             find_child(chi);
45 
46             st[d] += st[chi];
47         }
48 }
49 
50 void solve(int d)
51 {
52     if (d!=1)
53         value[d] = value[ fa[d] ] - st[d] + (st[1]-st[d]);
54 
55         //value[d] = value[ fa[d] ] - ( c[ fa[d] ] * st[d] ) + ( c[d] * (c[1]-st[d]) );
56     for (int chi:child[d])
57         solve(chi);
58 }
59 
60 int main()
61 {
62     LL a,b,i;
63     cin>>n;
64     for (i=1;i<n;i++)
65     {
66         cin>>a>>b;
67         adj[a].push_back(b);
68         adj[b].push_back(a);
69     }
70     for (i=1;i<=n;i++)
71         cin>>c[i];
72 
73     high[1]=0;
74     find_child(1);
75 
76     memset(value,0,sizeof(value));
77     value[1]=0;
78     for (i=1;i<=n;i++)
79         value[1]+=high[i]*c[i];
80 
81     solve(1);
82 
83     for (i=1;i<=n;i++)
84         result=min(result, value[i]);
85 
86     cout<<result;
87 
88     return 0;
89 }

 

 

 

D

感觉做的时候有点晕。

写了两种方法。

第一种:

一开始是dfs,x,y坐标,记录当前这个位置可以达到的最大E值(energy),若遍历得到的新的E值没有比现在的好,就不做遍历。最坏时间复杂度是h*w*E   E=h*w,这样看的话是要超时的

我还添加了T点(终点)到所有点的最短距离,如果到达某一点后,可以直接到达T点,那么输出Yes结束。如果用dfs和这个,还是超时。

但是这样超时,于是dfs改为优先队列,创建E值从大到小的堆。

所有样例6ms内就解决了,让人很诧异。大概是因为有了【若遍历得到的新的E值没有比现在的好,就不做遍历】的约束,再加上【优先队列保证E值优先跑最大的】,所有基本上跑的都是最优方案,绝大部分次一点的方案没有跑。

然后有了这个后,前面的那个T点距离优化可以不用加,不加的话,运行时间从6ms变为8ms。

 

 

第二种:

S、T点(起点、终点)和有药物的点,它们可以用bfs的方式去处理。

从T点(终点)倒推。

如果现在在U点,前面已经证实了可以从U点到T点(终点)。如果U点倒推到下一个点R点,那么R点也可以到T点。U点倒推到下一个点R点,前提是U点到R点的距离,要小于等于R点有的药物值,这样的话,R点可以走到T点。

然后S、T点(起点、终点)和有药物的点,它们两两求它们之间的距离,同样也是bfs去处理。这个的时间复杂度是O(n^2*h*w)。

有点那种点压缩的感觉,就像tarjan分为若干个子块一样。

 

 

Sol1

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <cstdbool>
  6 #include <string>
  7 #include <algorithm>
  8 #include <iostream>
  9 #include <sstream>
 10 #include <ctime>
 11 #include <stack>
 12 #include <vector>
 13 #include <queue>
 14 #include <set>
 15 #include <map>
 16 #include <array>
 17 #include <bitset>
 18 using namespace std;
 19 #define LL long long
 20 #define ULL unsigned long long
 21 
 22 const LL mod_1=1e9+7;
 23 const LL mod_2=998244353;
 24 
 25 const double eps_1=1e-5;
 26 const double eps_2=1e-10;
 27 
 28 const int maxn=2e2+10;
 29 
 30 bool stop[maxn][maxn];
 31 
 32 int maxE[maxn][maxn];
 33 
 34 int med[maxn][maxn];
 35 
 36 int dx[4]={0,0,1,-1};
 37 int dy[4]={1,-1,0,0};
 38 int row,col,tx,ty;
 39 
 40 
 41 bool use[maxn][maxn];
 42 int qx[maxn*maxn], qy[maxn*maxn], step[maxn][maxn];
 43 bool judge[maxn][maxn];
 44 
 45 priority_queue< array<int, 3> > que;
 46 
 47 
 48 ///siz=row*col O(siz*E) = 1600000000
 49 ///有没有方法证明这个方法复杂度会低一点/很多?
 50 ///AC 49 ; TLE 4
 51 
 52 void dfs(int x, int y)
 53 {
 54     int i,xx,yy;
 55     ///======
 56 
 57     /**
 58     1. 还是4TLE
 59     2. 先往终点/step[x][y]小的方向走?
 60     3. 按照E的能量排序走?
 61     4. 优先队列?
 62     **/
 63 
 64     if (x==tx && y==ty)
 65     {
 66         cout<<"Yes"<<endl;
 67         exit(0);
 68     }
 69     if (maxE[x][y]>=step[x][y])
 70     {
 71         cout<<"Yes"<<endl;
 72         exit(0);
 73     }
 74 
 75     ///======
 76 
 77     for (i=0;i<4;i++)
 78     {
 79         xx=x+dx[i];
 80         yy=y+dy[i];
 81 
 82         if (xx>=0 && xx<row && yy>=0 && yy<col && stop[xx][yy]==0 && maxE[x][y]-1>maxE[xx][yy])
 83         {
 84             maxE[xx][yy]=max(maxE[x][y]-1, med[xx][yy]);
 85             dfs(xx,yy);
 86         }
 87     }
 88 }
 89 
 90 int main()
 91 {
 92     int i,j;
 93     int q,sx,sy,x,y,e;
 94     char ch;
 95     int head,tail,xx,yy;
 96     memset(stop,0,sizeof(stop));
 97     scanf("%d%d%c",&row,&col,&ch);
 98     for (i=0;i<row;i++)
 99     {
100         for (j=0;j<col;j++)
101         {
102             scanf("%c",&ch);
103             if (ch=='#')
104                 stop[i][j]=1;
105             else if (ch=='S')
106                 sx=i, sy=j;
107             else if (ch=='T')
108                 tx=i, ty=j;
109         }
110         scanf("%c",&ch);
111     }
112 
113     memset(med,0,sizeof(med));
114     scanf("%d",&q);
115     while (q--)
116     {
117         scanf("%d%d%d",&x,&y,&e);
118         x--, y--;
119         med[x][y]=e;
120     }
121 
122 
123     memset(use,0,sizeof(use));
124     memset(step,127 ,sizeof(step));
125     head=0, tail=1;
126     qx[1]=tx, qy[1]=ty, use[tx][ty]=1, step[tx][ty]=0;
127     while (head<tail)
128     {
129         head++;
130         x=qx[head], y=qy[head];
131 
132         for (i=0;i<4;i++)
133         {
134             xx=x+dx[i];
135             yy=y+dy[i];
136 
137             if (xx>=0 && xx<row && yy>=0 && yy<col && stop[xx][yy]==0 && !use[xx][yy])
138             {
139                 tail++;
140                 qx[tail]=xx, qy[tail]=yy, use[xx][yy]=1, step[xx][yy]=step[x][y]+1;
141             }
142         }
143     }
144     /*
145     for (i=0;i<row;i++)
146     {
147         for (j=0;j<col;j++)
148             printf("%d ",step[i][j]);
149         printf("\n");
150     }
151     */
152 
153     memset(maxE,0xff,sizeof(maxE));
154     maxE[sx][sy]=med[sx][sy];
155     memset(judge,0,sizeof(judge));
156     //dfs(sx,sy);
157 
158     ///*
159     que.push({med[sx][sy],sx,sy});
160     while (!que.empty())
161     {
162         auto temp=que.top();
163         que.pop();
164         e=temp[0], x=temp[1], y=temp[2];
165         if (maxE[x][y]>e)
166             continue;
167 
168         //maxE[x][y]=e;
169         ///judge[x][y]=1;
170         //cout<<"test "<<e<<" "<<x<<" "<<y<<endl;
171 
172         if (x==tx && y==ty)
173         {
174             cout<<"Yes"<<endl;
175             exit(0);
176         }
177         if (maxE[x][y]>=step[x][y])
178         {
179             cout<<"Yes"<<endl;
180             exit(0);
181         }
182 
183         for (i=0;i<4;i++)
184         {
185             xx=x+dx[i];
186             yy=y+dy[i];
187 
188             if (xx>=0 && xx<row && yy>=0 && yy<col && stop[xx][yy]==0 && e-1>maxE[xx][yy])  /// && !judge[xx][yy]
189             {
190                 //maxE[xx][yy]=e-1;
191                 maxE[xx][yy]=max(e-1, med[xx][yy]);
192                 que.push({maxE[xx][yy],xx,yy});
193             }
194         }
195     }
196     //*/
197 
198     ///药物只能吃一次:其实最多只需要吃一次。这个条件就可以去掉
199 
200 
201     cout<<"No"<<endl;
202 
203     return 0;
204 }
205 /*
206 6 6
207 ...#.#
208 ....S#
209 ......
210 ####.#
211 ####.#
212 ####T#
213 1
214 2 5 4
215 
216 ======
217 
218 6 6
219 ...#.#
220 ....S#
221 ......
222 ####.#
223 ####.#
224 ####T#
225 1
226 2 5 3
227 
228 ======
229 
230 6 6
231 ...#.#
232 ....S#
233 ....#.
234 ####.#
235 ####.#
236 ####T#
237 1
238 2 5 4
239 
240 ======
241 
242 
243 */

 

 

Sol2

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <cstdbool>
  6 #include <string>
  7 #include <algorithm>
  8 #include <iostream>
  9 #include <sstream>
 10 #include <ctime>
 11 #include <stack>
 12 #include <vector>
 13 #include <queue>
 14 #include <set>
 15 #include <map>
 16 #include <array>
 17 #include <bitset>
 18 using namespace std;
 19 #define LL long long
 20 #define ULL unsigned long long
 21 
 22 const LL mod_1=1e9+7;
 23 const LL mod_2=998244353;
 24 
 25 const double eps_1=1e-5;
 26 const double eps_2=1e-10;
 27 
 28 const int maxn=2e2+10;
 29 const int maxg=maxn*maxn;
 30 const int maxz=3e2+10; ///maxzhongzhuan
 31 
 32 bool stop[maxn][maxn];
 33 
 34 int maxE[maxn][maxn];
 35 
 36 int med[maxn][maxn];
 37 
 38 int dx[4]={0,0,1,-1};
 39 int dy[4]={1,-1,0,0};
 40 int row,col,sx,sy,tx,ty;
 41 
 42 bool use[maxn][maxn];
 43 int qx[maxg], qy[maxg], step[maxn][maxn];
 44 int cx[maxz],cy[maxz];
 45 int dist[maxz][maxz];
 46 //int zx[maxz],zy[maxz];
 47 int qindex[maxz];
 48 bool judge[maxz];
 49 
 50 
 51 int main()
 52 {
 53     int i,j;
 54     int q,x,y,e;
 55     char ch;
 56     int head,tail,xx,yy;
 57     int index;
 58 
 59     memset(stop,0,sizeof(stop));
 60     scanf("%d%d%c",&row,&col,&ch);
 61     for (i=0;i<row;i++)
 62     {
 63         for (j=0;j<col;j++)
 64         {
 65             scanf("%c",&ch);
 66             if (ch=='#')
 67                 stop[i][j]=1;
 68             else if (ch=='S')
 69                 sx=i, sy=j;
 70             else if (ch=='T')
 71                 tx=i, ty=j;
 72         }
 73         scanf("%c",&ch);
 74     }
 75 
 76     memset(med,0,sizeof(med));
 77     scanf("%d",&q);
 78     for (i=1;i<=q;i++)
 79     {
 80         scanf("%d%d%d",&x,&y,&e);
 81         x--, y--;
 82         cx[i]=x, cy[i]=y;
 83         med[x][y]=e;
 84     }
 85 
 86     ///======
 87 
 88     cx[q+1]=sx, cy[q+1]=sy;
 89     cx[q+2]=tx, cy[q+2]=ty;
 90     q+=2;
 91 
 92     for (j=1;j<=q;j++)
 93     {
 94         memset(use,0,sizeof(use));
 95         memset(step,127 ,sizeof(step));
 96         head=0, tail=1;
 97         qx[1]=cx[j], qy[1]=cy[j], use[qx[1]][qy[1]]=1, step[qx[1]][qy[1]]=0;
 98         while (head<tail)
 99         {
100             head++;
101             x=qx[head], y=qy[head];
102 
103             for (i=0;i<4;i++)
104             {
105                 xx=x+dx[i];
106                 yy=y+dy[i];
107 
108                 if (xx>=0 && xx<row && yy>=0 && yy<col && stop[xx][yy]==0 && !use[xx][yy])
109                 {
110                     tail++;
111                     qx[tail]=xx, qy[tail]=yy, use[xx][yy]=1, step[xx][yy]=step[x][y]+1;
112                 }
113             }
114         }
115         for (i=1;i<=q;i++)
116             dist[j][i]=step[ cx[i] ][ cy[i] ];
117     }
118 
119 
120     head=0, tail=1;
121     memset(judge,0,sizeof(judge));
122     qindex[1]=q, judge[ qindex[1] ]=1;  ///q === t
123     while (head<tail)
124     {
125         head++;
126         index=qindex[head];
127 
128         if (index==q-1) ///q-1 == s
129         {
130             cout<<"Yes"<<endl;
131             exit(0);
132         }
133 
134         for (i=1;i<=q;i++)
135             if (i!=index && !judge[i] && dist[index][i] <= med[ cx[i] ][ cy[i] ])
136             {
137                 tail++;
138                 qindex[tail]=i, judge[i]=1;
139             }
140     }
141 
142     cout<<"No"<<endl;
143 
144     return 0;
145 }

 

 

F

就很有bitset的感觉。

本来是n*n/2*m的复杂度,直接暴力的话,但是这样超时。

但是没有除了暴力以外的方法。题目处理的是两个序列的比较,序列可以转化为bitset,可以时间和空间复杂度都能降低。

记录第j列,选取的数值为a[i][j]时,这个列(和其它列是单独孤立的)当选择数值为a[i][j],所有序列和它是否相同。如果这一列是 3 4 5 4 2,如果a[i][j]=3,那么它是10000,如果a[i][j]=4,那么它是01010。

问题转化为一个序列,和其它序列的bitset处理。

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <cstdbool>
  6 #include <string>
  7 #include <algorithm>
  8 #include <iostream>
  9 #include <sstream>
 10 #include <ctime>
 11 #include <stack>
 12 #include <vector>
 13 #include <queue>
 14 #include <set>
 15 #include <map>
 16 #include <array>
 17 #include <bitset>
 18 using namespace std;
 19 #define LL long long
 20 #define ULL unsigned long long
 21 
 22 const LL mod_1=1e9+7;
 23 const LL mod_2=998244353;
 24 
 25 const double eps_1=1e-5;
 26 const double eps_2=1e-10;
 27 
 28 const int maxn=2e3+10;
 29 const int maxm=2e3+10;
 30 const int maxa=1e3+10;
 31 
 32 bitset<maxn> bs[maxm][maxa];
 33 int a[maxn][maxm];
 34 bitset<maxn> cur;
 35 
 36 int main()
 37 {
 38     int n,m,i,j,cnt=0;
 39 
 40     scanf("%d%d",&n,&m);
 41     for (i=0;i<n;i++)
 42     {
 43         for (j=0;j<m;j++)
 44         {
 45             scanf("%d",&a[i][j]);
 46             bs[j][ a[i][j] ][i]=1;
 47         }
 48     }
 49 
 50     for (i=0;i<n;i++)
 51     {
 52         cur.reset();
 53         for (j=0;j<m;j++)
 54             cur=cur ^ bs[j][ a[i][j] ]; ///xor
 55 
 56         /*
 57         cout<<"test i="<<i<<" ";
 58         for (j=0;j<n;j++)
 59             cout<<cur[j];
 60         cout<<endl;
 61         */
 62 
 63         cnt += cur.count();
 64     }
 65 
 66     if (m & 1)
 67         cnt-=n;
 68 
 69     printf("%d",cnt/2);
 70 
 71     return 0;
 72 }
 73 /*
 74 4 4
 75 1 1 1 1
 76 1 1 1 1
 77 1 1 1 1
 78 1 1 1 1
 79 
 80 ======
 81 
 82 5 4
 83 1 1 1 1
 84 1 1 1 1
 85 1 1 1 1
 86 1 1 1 1
 87 1 1 1 1
 88 
 89 ======
 90 
 91 5 5
 92 1 1 1 1 1
 93 1 1 1 1 1
 94 1 1 1 1 1
 95 1 1 1 1 1
 96 1 1 1 1 1
 97 
 98 ======
 99 
100 
101 
102 */

 

 

 

也可以参考 AtCoder Beginner Contest 348 A 至 F 題讲解 by dreamoon_哔哩哔哩_bilibili

 

posted @ 2024-04-12 19:49  congmingyige  阅读(21)  评论(0编辑  收藏  举报