ABC368 D-G题解 (AtCoder Beginner Contest 368)

 

D

树从叶子到根,对于某个点,如果其子树不存在需要的点,那么这个点和它的父亲所连的边,自然不需要,否则需要。

有一个问题,比如需要点2、4、5,那么点1和点2所连的边也算进去了。实际上,到了它们的LCS(最大公共祖先)后,这些边就不用算了。用一个变量统计当前遍历过多少需要的点,如果所有需要的点恰好都遍历过了,那么当前遍历的点为LCS,直接退出即可。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define ULL unsigned long long
 5 
 6 const LL mod_1=1e9+7;
 7 const LL mod_2=998244353;
 8 
 9 const double eps_1=1e-5;
10 const double eps_2=1e-10;
11 
12 const int maxn=2e5+10;
13 
14 vector<int> adj[maxn];
15 bool vis[maxn];
16 int k,r=0,value[maxn];
17 
18 void dfs(int d)
19 {
20     vis[d]=1;
21     for (auto dd:adj[d])
22         if (!vis[dd])
23         {
24             dfs(dd);
25             value[d]+=value[dd];
26         }
27     if (value[d]>0)
28         r++;
29     if (value[d]==k)
30     {
31         cout<<r;
32         exit(0);
33     }
34 }
35 
36 int main()
37 {
38     int n,i,a,b;
39     cin>>n>>k;
40     for (i=1;i<n;i++)
41     {
42         cin>>a>>b;
43         adj[a].push_back(b);
44         adj[b].push_back(a);
45     }
46     memset(value,0,sizeof(value));
47     for (i=1;i<=k;i++)
48     {
49         cin>>a;
50         value[a]=1;
51     }
52     memset(vis,0,sizeof(vis));
53     dfs(1);
54     return 0;
55 }

 

 

E

T(到达时间)从小到大排序。
对于某一项,先确定X的值(即这一趟至少要延迟多长时间):对于这一站的起始城市Aj,即上一趟转乘的到达城市Bi(Aj=Bi),找到城市Bi中到达时间(Ti)<=这一项的出发时间(Sj)中,到达+延迟时间最大(Ti+Xi)的,然后和这一项的出发时间(Sj)做比较,取max,从而也获得了这一项的X的值,X=max( max{Ti+Xi} - Sj, 0)。
然后对于这一项的到达城市Bj,更新对于城市Bj,到达 / 到达+延迟时间的信息(记录第一个是到达时间,记录第二个对应的到达+延迟时间,城市Bj的这两项信息按到达时间从小到大的排序)。
X0也有可能在非首位(T最小)的位置

 

实际上,这道题挺好写的,不难。最少人做和做对,估计是:

1. 题意长,题面看着繁琐(挺多公式、变量),比较难懂,劝退了不少人

2. 实际上写方法、代码,也比较绕

3. G相对好做,大家先做了G

无法理解这么多WA,是因为它们没有考虑“X0也有可能在非首位(T最小)的位置”,这个?

TLE不少,难道是它们都尝试暴力做?或者是有什么"环“??没有对T进行排序?

另外,我看codeforces的讨论,E的讨论挺多的,它们有的往图的角度想,自然做不出来。

 

 

 1 /*
 2 T(到达时间)从小到大排序。
 3 对于某一项,先确定X的值(即这一趟至少要延迟多长时间):对于这一站的起始城市Aj,即上一趟转乘的到达城市Bi(Aj=Bi),找到城市Bi中到达时间(Ti)<=这一项的出发时间(Sj)中,到达+延迟时间最大(Ti+Xi)的,然后和这一项的出发时间(Sj)做比较,取max,从而也获得了这一项的X的值,X=max( max{Ti+Xi} - Sj, 0)。
 4 然后对于这一项的到达城市Bj,更新对于城市Bj,到达 / 到达+延迟时间的信息(记录第一个是到达时间,记录第二个对应的到达+延迟时间,城市Bj的这两项信息按到达时间从小到大的排序)。
 5 X0也有可能在非首位(T最小)的位置
 6 */
 7 #include <bits/stdc++.h>
 8 using namespace std;
 9 #define LL long long
10 #define ULL unsigned long long
11 
12 const LL mod_1=1e9+7;
13 const LL mod_2=998244353;
14 
15 const double eps_1=1e-5;
16 const double eps_2=1e-10;
17 
18 const int maxn=2e5+10;
19 
20 LL x[maxn];
21 //a[maxn],b[maxn],s[maxn],t[maxn]
22 struct node
23 {
24     LL a,b,s,t,index;
25     bool operator<(node v)
26     {
27         return t < v.t;
28     }
29 } info[maxn];
30 
31 vector<LL> lat[maxn], tim[maxn];
32 
33 int main()
34 {
35     LL n,m,i,a,b,add;
36     memset(x,0,sizeof(x));
37     cin>>n>>m>>x[1];
38     for (i=1;i<=m;i++)
39     {
40         //cin>>a[i]>>b[i]>>s[i]>>t[i];
41         cin>>info[i].a>>info[i].b>>info[i].s>>info[i].t;
42         info[i].index=i;
43     }
44     sort(info+1,info+m+1);
45 
46     //cout<<"test "<<info[1].t<<endl;
47 
48     for (i=1;i<=m;i++)
49         if (info[i].index==1)
50             break;
51 
52     b = info[i].b;
53     tim[b].push_back( info[i].t );
54     lat[b].push_back( info[i].t + x[1] );
55 
56     while (i<=m)
57     {
58         i++;
59 
60         a = info[i].a;
61         auto it = upper_bound(tim[a].begin(), tim[a].end(), info[i].s);
62         if (it==tim[a].begin())
63             continue;
64         
65         it--;
66         add = max( *(it-tim[a].begin() + lat[a].begin()) - info[i].s , 0LL);
67         x[ info[i].index ] = add;
68 
69         if (add!=0)
70         {
71             b = info[i].b;
72             if (lat[b].empty() || lat[b].back() < info[i].t + add)
73             {
74                 tim[b].push_back(info[i].t);
75                 lat[b].push_back(info[i].t+add);
76             }
77         }
78     }
79 
80     for (i=2;i<=m;i++)
81     {
82         cout<<x[i];
83         if (i!=m)
84             cout<<" ";
85     }
86 
87     return 0;
88 }

 

 

F

这么多人做和做对,怀疑用了chatgpt,emmm。现在数论题,感觉chatgpt很容易搜出正确方法。

 

实际上,写代码过程中,vscode自动补全了很多代码。

 

公平组合游戏 - OI Wiki (oi-wiki.org)

 

所有SG(x)可以进行进行初始化。

求一个数的质因数,因为是1e5范围,可以用比较快、不容易写错的方式写。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define ULL unsigned long long
 5 
 6 const LL mod_1=1e9+7;
 7 const LL mod_2=998244353;
 8 
 9 const double eps_1=1e-5;
10 const double eps_2=1e-10;
11 
12 const int maxn=1e5+10;
13 
14 vector<int> zys[maxn];
15 int sg[maxn];
16 
17 int main()
18 {
19     int n,i,j,x,max_sg=1e5,r=0;
20     vector<int> vec;
21 
22     for (i=1;i<=max_sg;i++)
23     {
24         for (j=i+i;j<=max_sg;j+=i)
25             zys[j].push_back(i);
26     }
27     sg[1]=0;
28     for (i=2;i<=max_sg;i++)
29     {
30         vec.clear();
31         for (auto z:zys[i])
32             vec.push_back(sg[z]);
33         sort(vec.begin(),vec.end());
34         vec.erase(unique(vec.begin(),vec.end()),vec.end());
35         for (j=0;j<vec.size();j++)
36             if (vec[j]!=j)
37                 break;
38         sg[i]=j;
39     }
40     
41     cin>>n;
42     for (i=1;i<=n;i++)
43     {
44         cin>>x;
45         r^=sg[x];
46     }
47 
48     if (r==0)
49         cout<<"Bruno"<<endl;
50     else
51         cout<<"Anna"<<endl;
52 
53     return 0;
54 }

 

 

最基础的SG:nim几堆,每次可以拿一堆的任意数目

 1 /*
 2 TODO 找例题做:
 3     https://www.cnblogs.com/AWhiteWall/p/14403827.html
 4     https://www.luogu.com.cn/article/1am7gm8b
 5 */
 6 #include <bits/stdc++.h>
 7 using namespace std;
 8 #define LL long long
 9 #define ULL unsigned long long
10 
11 const LL mod_1=1e9+7;
12 const LL mod_2=998244353;
13 
14 const double eps_1=1e-5;
15 const double eps_2=1e-10;
16 
17 const int maxn=2e5+10;
18 
19 vector<int> vec;
20 int sg[maxn];
21 
22 int main()
23 {
24     int i,j,n=10;
25     sg[0] = 0;
26     vec.push_back(sg[0]);
27     for (i=1;i<=n;i++)
28     {
29         for (j=0;j<vec.size();j++)
30             if (vec[j]!=j)
31                 break;
32         sg[i]=j;
33 
34         vec.push_back(sg[i]);
35     }
36 
37     for (i=0;i<=n;i++)
38         cout<<sg[i]<<" ";
39     //0 1 2 3 4 5 6 7 8 9 10
40 
41     return 0;
42 }

 

 1 //luogu P2197
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 #define LL long long
 5 #define ULL unsigned long long
 6 
 7 const LL mod_1=1e9+7;
 8 const LL mod_2=998244353;
 9 
10 const double eps_1=1e-5;
11 const double eps_2=1e-10;
12 
13 const int maxn=2e5+10;
14 
15 int main()
16 {
17     int T,n,i,x,r;
18     cin>>T;
19     while (T--)
20     {
21         r=0;
22         cin>>n;
23         for (i=0;i<n;i++)
24         {
25             cin>>x;
26             r^=x;
27         }
28         if (r==0)
29             cout<<"No"<<endl;
30         else
31             cout<<"Yes"<<endl;
32     }
33 
34     return 0;
35 }

 

 

 

UVA 1482

 

 

  1 /*
  2 https://vjudge.net/problem/UVA-1482
  3 https://www.luogu.com.cn/problem/UVA1482
  4 
  5 要写成1LL<<k,对于long long
  6 */
  7 #include <bits/stdc++.h>
  8 using namespace std;
  9 #define LL long long
 10 #define ULL unsigned long long
 11 
 12 const LL mod_1=1e9+7;
 13 const LL mod_2=998244353;
 14 
 15 const double eps_1=1e-5;
 16 const double eps_2=1e-10;
 17 
 18 const int maxn=2e5+10;
 19 
 20 int sg[maxn], valid_sg[maxn];
 21 vector<int> vec;
 22 
 23 void get_sg()
 24 {
 25     int n=1000,i,j,k,siz;
 26     sg[0]=0;
 27     sg[1]=0;
 28     
 29     for (i=2;i<=n;i++)
 30     {
 31         vec.clear();
 32         for (j=(i+1)/2;j<i;j++)
 33             vec.push_back(sg[j]);
 34         
 35         sort(vec.begin(), vec.end());
 36         vec.erase(unique(vec.begin(), vec.end()), vec.end());
 37 
 38         siz = vec.size();
 39         for (k=0;k<siz;k++)
 40             if (vec[k]!=k)
 41                 break;
 42         sg[i]=k;
 43     }
 44 
 45     for (i=1;i<=n;i++)
 46         cout<<sg[i]<<" ";
 47 }
 48 
 49 void validate()
 50 {
 51     int n=1000,i,j,cnt;
 52     
 53     for (i=1;i<=n;i++)
 54     {
 55         j=i;
 56         cnt=1;
 57         while (j)
 58         {
 59             if (j%2)
 60                 cnt++;
 61             else
 62                 break;
 63             j/=2;
 64         }
 65 
 66         valid_sg[i] = (i - (1<<(cnt-1)) + 1) / (1<<cnt);
 67     }
 68 
 69     for (i=1;i<=n;i++)
 70         if (sg[i]!=valid_sg[i])
 71             cout<<"wrong "<<i<<endl;
 72 }
 73 
 74 int main()
 75 {
 76     /*
 77     get_sg();
 78     validate();
 79     return 0;
 80     */
 81     
 82     LL T,n,cnt=0,r,a,i;
 83     cin>>T;
 84     while (T--)
 85     {
 86         r=0;
 87         cin>>n;
 88         while (n--)
 89         {
 90             cin>>a;
 91 
 92             i=a;
 93             cnt=1;
 94             while (i)
 95             {
 96                 if (i%2)
 97                     cnt++;
 98                 else
 99                     break;
100                 i/=2;
101             }
102 
103             r ^= (a - (1LL<<(cnt-1LL)) + 1LL) / (1LL<<cnt);
104 
105         }
106         
107         if (r)
108             cout<<"YES"<<endl;
109         else
110             cout<<"NO"<<endl;
111     }
112     
113 
114 
115     return 0;
116 }

 

 

G

可以看这个:AtCoder Beginner Contest 368 - ~Lanly~ - 博客园 (cnblogs.com)

看standing,非常多人做出来。

其实样例1给了提示,在乘积为2的情况下,都选择加号,1+2+4=7。

如果Bi不为1,下一次B_{i+1}最小的数值必大于等于Bi*2。因为数目要小于等于10^18,2^60是最多了。即最多60次左右的乘法操作,然后相邻的加法操作要统一处理,由于加法和乘法是间隔的,所以加法操作也最多60次左右。

 

统计Bi="1"的区间,这样可以方便快速跳过它。

Ai区间和,统计Bi="1"的区间,都用树状数组来做。

对于区间首个Bi=1,用二分获取下一个非Bi=1的位置。

 

样例:

8
1 2 3 4 5 6 7 8
1 1 1 2 1 1 3 1
1
3 1 8

output:
77

 

1 1 1 2 1 1 3 1 以此分为若干组

 

  1 /*
  2 先分析Ai、Bj不进行修改时,怎么求Type 3
  3 */
  4 #include <bits/stdc++.h>
  5 using namespace std;
  6 #define LL long long
  7 #define ULL unsigned long long
  8 
  9 const LL mod_1=1e9+7;
 10 const LL mod_2=998244353;
 11 
 12 const double eps_1=1e-5;
 13 const double eps_2=1e-10;
 14 
 15 const int maxn=1e5+10;
 16 
 17 LL a[maxn], b[maxn],ca[maxn],cb[maxn];
 18 
 19 LL n;
 20 
 21 void update(LL * arr, LL x, LL y)
 22 {
 23     LL i;
 24     for (i=x;i<=n;i+=i&-i)
 25         arr[i]+=y;
 26 }
 27 
 28 LL getsum(LL * arr, LL x)
 29 {
 30     LL i,ans=0;
 31     for (i=x;i>=1;i-=i&-i)
 32         ans+=arr[i];
 33     return ans;
 34 }
 35 
 36 int main()
 37 {
 38     LL i,q,type,l,r,value,num1,num2,w,l_old;
 39     memset(ca,0,sizeof(ca));
 40     memset(cb,0,sizeof(cb));
 41     cin>>n;
 42     for (i=1;i<=n;i++)
 43     {
 44         cin>>a[i];
 45         update(ca,i,a[i]);
 46     }
 47     for (i=1;i<=n;i++)
 48     {
 49         cin>>b[i];
 50         if (b[i]!=1)
 51             update(cb,i,1);
 52     }
 53 
 54     cin>>q;
 55     while (q--)
 56     {
 57         cin>>type>>l>>r;
 58         if (type==1)
 59         {
 60             update(ca,l,r-a[l]);
 61             a[l]=r;
 62         }
 63         else if (type==2)
 64         {
 65             if (b[l]==1 && r!=1)
 66                 update(cb,l,1);
 67             else if (b[l]!=1 && r==1)
 68                 update(cb,l,-1);
 69             b[l]=r;
 70         }
 71         else
 72         {
 73             value=0;
 74             while (l<=r)
 75             {
 76                 while (b[l]!=1 && l<=r)
 77                 {
 78                     value = max(value+a[l], value*b[l]);
 79                     l++;
 80                 }
 81                 if (l>r)
 82                     break;
 83 
 84                 l_old = l;
 85                 num1 = getsum(cb,l);
 86                 for (w = (LL)ceil( log(r-l)/log(2)+eps_2 ) ; w>=0; w--)
 87                 {
 88                     if (l+(1<<w)>r)
 89                         continue;
 90                     num2 = getsum(cb,l+(1<<w));
 91                     if (num1==num2)
 92                     {
 93                         l+=(1<<w);
 94                         num1 = num2;
 95                     }
 96                 }
 97                 value += getsum(ca,l)-getsum(ca,l_old-1);
 98                 l++;
 99             }
100             cout<<value<<endl;
101         }
102     }
103 
104     return 0;
105 }

 

posted @ 2024-08-27 17:33  congmingyige  阅读(19)  评论(0编辑  收藏  举报