2020牛客暑期多校训练营(第九场)

AEFIK

A. Groundhog and 2-Power Representation

题意

一个数可以由2x1+2x2+2x3+.....组成,例如1315=210+28+25+2+1=2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0).
现在给出一个由2的次幂组成的表达式,输出这个数是多少。

题解

不得不说py真的强,看到不到2分钟就有人a了,还以为是原题,赛后发现py三行。(暴风哭泣
我队用的c++高精度模拟写的,队友%%%

代码

py
1 n = input()
2 n = n.replace("(","**(")
3 print(eval(n))
View Code

c++

  1 #include<bits/stdc++.h>
  2 #define pb push_back
  3 using namespace std;
  4 typedef long long ll;
  5 const int inf = 0x3f3f3f3f;
  6 const ll INF = 0x3f3f3f3f3f3f3f3f;
  7 const int maxn = 3e4+10;
  8  
  9 vector<int> mult(vector<int>x,vector<int>y)//高精*高精
 10 {
 11     int xlen=(int)x.size(),ylen=(int)y.size(),zlen=xlen+ylen;
 12     vector<int>z(zlen);
 13     for(register int i=0;i<xlen;i++)
 14         for(register int j=0;j<ylen;j++)
 15             z[i+j]+=x[i]*y[j];
 16     for(register int i=0;i<zlen;i++)
 17         if(z[i]>9)
 18         {
 19             z[i+1]+=z[i]/10;
 20             z[i]%=10;
 21         }
 22     while(zlen>1 && !z.back())
 23     {
 24         z.pop_back();
 25         zlen--;
 26     }
 27     return z;
 28 }
 29 vector<int> chu(int x,vector<int> vv)
 30 {
 31     bool flag=false;
 32     vector<int> ans;
 33     int t=0;
 34     int i;
 35     for (i=vv.size()-1; i>=0; i-- )
 36     {
 37         t=t*10+vv[i];
 38         if(flag)
 39         {
 40             ans.push_back(t/x);
 41         }
 42         else if(t/x>0)
 43         {
 44             flag=true;
 45             ans.push_back(t/x);
 46         }
 47         t=t%x;
 48     }
 49     return vector<int> (ans.rbegin(),ans.rend());
 50 }
 51 vector<int> add(vector<int>x,vector<int>y)//高精+高精
 52 {
 53     int xlen=(int)x.size(),ylen=(int)y.size(),zlen=max(xlen,ylen)+1;
 54     vector<int>z(zlen);
 55     for(register int i=0;i<zlen;i++)
 56     {
 57         if(i<xlen)
 58             z[i]+=x[i];
 59         if(i<ylen)
 60             z[i]+=y[i];
 61         if(z[i]>9)
 62         {
 63             z[i+1]++;
 64             z[i]-=10;
 65         }
 66     }
 67     while(zlen>1 && !z.back())
 68     {
 69         zlen--;
 70         z.pop_back();
 71     }
 72     return z;
 73 }
 74 void prin(vector<int> x)
 75 {
 76     int i;
 77     if(x.size() == 0)
 78     {
 79         printf("0");
 80     }
 81     for (i=x.size()-1;i>=0;i--)
 82     {
 83         printf("%d",x[i]);
 84     }
 85     printf("\n");
 86 }
 87 std::vector<int> qup(std::vector<int> vv)
 88 {
 89     std::vector<int> ans;
 90     ans.pb(1);
 91     std::vector<int> v;
 92     std::vector<int> f;
 93     f.pb(0);
 94     v.pb(2);
 95     while(vv.size() > 0 && *(--vv.end()) != 0)
 96     {
 97         if(vv[0] & 1)
 98             ans = mult(v,ans);
 99         vv = chu(2,vv);
100         v = mult(v,v);
101     }
102     return ans;
103 }
104  
105 char a[maxn];
106 vector<int> dg(int l,int r)
107 {
108     vector<int> ans;
109      
110     if(l == r)
111     {
112         ans.pb(a[l] - '0');
113         return ans;
114     }
115     ans.pb(0);
116     std::vector<int> temp;
117     for (int i = l; i <= r; i ++ )
118     {
119          
120         if(a[i] == '(')
121         {
122             int s= 0 ;
123             for(int j = i + 1; j <= r; j ++ )
124             {
125                 if(a[j] == '(')
126                     s ++ ;
127                 if(a[j] == ')')
128                 {
129                     if(s == 0)
130                     {
131                         ans = add(ans,qup(dg(i + 1, j - 1)));
132                         i = j;
133                         break;
134                     }
135                     else
136                         s -- ;
137                 }
138             }
139             continue;
140         }
141         if(a[i] == '+')
142         {
143             ans = add(ans,dg(i + 1,r));
144             break;
145         }
146         else
147         {
148             if(a[i + 1] != '(')
149             {
150                 temp.pb(a[i] - '0');
151                 ans = add(ans,temp);
152             }
153             continue;
154         }
155     }
156     return ans;
157 }
158  
159 int main()
160 {
161     scanf("%s",a + 1);
162     int n = strlen(a + 1);
163     vector<int> ans = dg(1,n);
164     prin(ans);
165 }
View Code

 

E. Groundhog Chasing Death

题意

给出a,b,c,d,x,y,求∏(i=a,b)(j=c,d) gcd(xi,yj)  modulo 998244353的结果

题解

第一想法肯定是暴力:枚举 i 和 j ,然后算出每一个 gcd(x, yj),然后乘起来。但是数据 i 和 j 的数据范围都在1e6,这样肯定会超时,i 和 j 的范围在1e9,这样肯定是要爆long long的。那么就要想想怎么优化。
因为这是一个乘性函数,那么肯定要想到分解质因子,所以先预处理 x 的质因子,并记录每个质因子出现的次数,这样 x就可以由每个质因子个数再 *i 得到。枚举 x中因子 m 出现的次数,可以发现当 yj 小的时候,gcd(x, yj) 主要是被 yj 的 m 个数约束,此时是一个等差数列;当 yj 大的时候,就是由 x约束,此时 yj 中 m 的个数是一个常数,暴力求解就好了。
由于质因子的幂很大,会爆long long,所以要用欧拉降幂,欧拉降幂是对mod-1取模(队友对mod取模debug好久

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3  
  4 typedef long long ll;
  5 const ll mod = 998244353;
  6 const ll md = 998244352;
  7 vector<pair<ll,ll> > v;
  8  
  9 void div(ll n)
 10 {
 11     v.clear();
 12     ll k = sqrt(n);
 13     for (ll i = 2; i <= k; ++ i) {
 14         ll cnt = 0;
 15         while (n % i == 0) {
 16             n /= i;
 17             cnt ++;
 18         }
 19         v.push_back({i, cnt});
 20     }
 21     if (n != 1) {
 22         v.push_back({n, 1});
 23     }
 24 }
 25  
 26 ll phi(ll n)
 27 {
 28     ll ans = n;
 29     ll k = sqrt(n);
 30     for (int i = 2; i <= k; ++i) {
 31         if (n % i == 0) {
 32             ans = ans / i * (i - 1);
 33             while (n % i == 0) n /= i;
 34         }
 35     }
 36     if (n > 1) {
 37         ans = ans / n * (n - 1);
 38     }
 39     return ans;
 40 }
 41  
 42 ll pow(ll a, ll b, ll p) {
 43     ll res = 1;
 44     while (b) {
 45         if (b & 1) res = (res * a) % p;
 46         a = a * a % p;
 47         b >>= 1;
 48     }
 49     return res%p;
 50 }
 51  
 52 int main()
 53 {
 54     ll a, b, c, d, x, y;
 55     scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x, &y);
 56     a = max(1LL, a);
 57     c = max(1LL, c);
 58     --c;
 59     div(x);
 60     ll ans = 1;
 61     for (int i = 0; i < (int)v.size(); ++ i) {
 62         ll cnt = 0;
 63         while (y % v[i].first == 0) {
 64             y /= v[i].first;
 65             ++ cnt;
 66         }
 67         ll sum = 0;
 68         if (cnt == 0) continue;
 69         for (ll j = a; j <= b; ++ j) {
 70             ll e = v[i].second * (ll)j;
 71             ll f = e/cnt;
 72             while (cnt * f < e) {
 73                 ++ f;
 74             }
 75             if (c >= f) {
 76                 sum -= ((f * (f-1) / 2)% md * (cnt % md)) % md;
 77                 sum = (sum % md + md) % md;
 78                 sum -= (ll)(((c-f+1) % md) * (e % md)) % md;
 79                 sum = (sum % md + md) % md;
 80             }
 81             else {
 82                 sum -= ((c * (c+1) / 2) % md * (cnt % md)) % md;
 83                 sum = (sum % md + md) % md;
 84             }
 85             sum = (sum % md + md) % md;
 86             if (d >= f) {
 87                 sum += ((f * (f-1) / 2) % md) * (cnt % md) % md;
 88                 sum = (sum % md + md) % md;
 89                 sum += (ll)(((d-f+1) % md) * (e % md)) % md;
 90                 sum = (sum % md + md) % md;
 91             }
 92             else {
 93                 sum += (((d * (d+1) /2) % md) * (cnt) % md) % md;
 94                 sum = (sum % md + md) % md;
 95             }
 96         }
 97         sum = (sum % md + md) % md;
 98         ans *= pow(v[i].first, sum, mod);
 99         ans = (ans % mod + mod) % mod;
100     }
101     ans = (ans % mod + mod) % mod;
102     printf("%lld\n", ans);
103     return 0;
104 }
View Code

 

F. Groundhog Looking Dowdy

题意

土拨鼠要和苹果约会,第 i 天它的第 j 件衣服的邋遢度为 aij ,它要在n天中选择m天和苹果约会,要求选出的m天衣服的邋遢度的最大值和最小值的差值最小。

题解

因为要最小化最大值和最小值的差值,所以用pair存每件衣服的邋遢度和第几天,然后对邋遢度从小到大排序。那么问题就转换成了求一个区间 [L,R] ,使得这个区间覆盖m个不同的天,并且R的邋遢度-L的邋遢度最小。这个问题就可以用尺取解决了。对于每一个L,求出最小的合法的R,每次更新差值最小值即可。

代码

 1 #include<bits/stdc++.h>
 2 #define st first
 3 #define sd second
 4 #define ll long long
 5 #define pii pair<int,int>
 6 using namespace std;
 7  
 8 const int inf = 0x3f3f3f3f;
 9 const int maxn = 2e6+10;
10  
11 pii pp[maxn];
12 int vis[maxn];
13  
14 int main()
15 {
16     int n,m;
17     scanf("%d%d",&n,&m);
18     int cnt = 0;
19     for (int i = 1; i <= n; i ++ ){
20         int p;
21         scanf("%d",&p);
22         for (int j = 1; j <= p; j ++ ){
23             int x;
24             scanf("%d",&x);
25             pp[++cnt].st = x;
26             pp[cnt].sd = i;
27         }
28     }
29     sort(pp + 1, pp + 1 + cnt);
30     int num = 0;
31     int l = 1, r = 1;
32     int minn = pp[1].st, maxx = 0;
33     int ans = inf;
34     while(1){
35         while(r <= cnt && num < m){
36             if(vis[pp[r].sd] == 0) num ++ ;
37             vis[pp[r].sd] ++ ;
38             maxx = pp[r].st;
39             r ++ ;
40         }
41         if(num < m)
42             break;
43         ans = min(ans, maxx - minn);
44         vis[pp[l].sd] -- ;
45         if(vis[pp[l].sd] == 0) num -- ;
46         minn = pp[l + 1].sd;
47         l ++ ;
48     }
49     printf("%d\n",ans);
50 }
View Code

 

I. The Crime-solving Plan of Groundhog

题意

给出n个数(0<=a[i]<=9),由这n个数组成2个数,使得这两个数的乘积最小。

题解

自己造几个例子就可以看出,选择0之外最小的数和剩下的数字组成的没有前导0的数相乘结果最小。剩下的数字怎样最小呢,当然是找到最小的非零的数做第一位,后边接上所有的0,再按照有小到大的顺序放剩下的数字。因为n的范围在1e5,所以要用高精度乘法。

推导:

把当前的数字拆成4个数 a, b, c, d (a ≤ b ≤ c ≤ d) ,那么我们有两种决策:两位数×两位数,或者三位数×一
位数。
(10a + d) * (10b + c) = 100ab + 10ac + 10bd + cd 
(100b+10c+d) * a = 100ab + 10ac +ad<(10a + d) * (10b + c)
同理,可以证明留一个最小的正整数作为第一个数,剩下的所有数字排成最小的数作为第二个数时,答案取到最小值。

代码

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4  
 5 int a[100100];
 6  
 7 int main()
 8 {
 9     ios::sync_with_stdio(false);
10     cin.tie(0);
11     cout.tie(0);
12     int t;
13     cin>>t;
14     while(t--){
15         int n;
16         cin>>n;
17         for(int i=0;i<n;i++) cin>>a[i];
18         sort(a,a+n);
19         int k=0;
20         while(k<n&&a[k]==0) k++;
21         vector<int>q;
22         q.push_back(a[k+1]);
23         for(int i=0;i<k;i++) q.push_back(0);
24         for(int i=k+2;i<n;i++) q.push_back(a[i]);
25         vector<int>ans;
26         for(int i=q.size()-1;i>=0;i--){
27             int x=q[i]*a[k];
28             ans.push_back(x);
29         }
30         for(int i=0;i<10;i++) ans.push_back(0);
31         for(int i=0;i<ans.size();i++){
32             if(ans[i]>=10){
33                 ans[i+1]+=ans[i]/10;
34                 ans[i]%=10;
35             }
36         }
37         while(!ans.back()) ans.pop_back();
38         for(int i=ans.size()-1;i>=0;i--) cout<<ans[i];
39         cout<<endl;
40     }
41     return 0;
42 }
View Code

 

K. The Flee Plan of Groundhog

题意

土拨鼠在第1个宿舍,橙子在第n个宿舍。这n个宿舍间有n-1条路并且长度都为1,土拨鼠从第1个房间去第n个宿舍,速度为1m/s;橙子从第n个宿舍追赶土拨鼠,速度为2m/s。

题解

二分时间 t ,然后判断在 ts 内土拨鼠是否会被橙子追上。以橙子所在的寝室 n 为根建树,从 1 到 n 枚举所有土拨鼠能够到达的点,先找出t秒能走到哪个点,然后再找这个点能走到的离n最远的点,判断在走的过程中会不会被追上。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3  
 4 const int maxn = 1e5+10;
 5 vector<int> vv[maxn];
 6 int vis[maxn];
 7 int f[maxn];
 8 int dep[maxn];
 9  
10 void dfs(int x,int fa,int de)
11 {
12     f[x] = fa;
13     dep[x] = de;
14     for (int i =0 ; i< vv[x].size(); i ++ )
15     {
16         int v = vv[x][i];
17         if(v == fa)
18             continue;
19         dfs(v,x,de + 1);
20         vis[x] |= vis[v];
21     }
22 }
23 int ans =0 ;
24 void dfs2(int x,int fa,int de)
25 {
26     ans = max(ans,de);
27     for (int i =0 ; i<vv[x].size(); i ++ )
28     {
29         int v = vv[x][i];
30         if(v == fa)
31             continue;
32         dfs2(v,x,de + 1);
33     }
34  
35 }
36 int main()
37 {
38     int n,m;
39     scanf("%d%d",&n,&m);
40     for (int i = 1; i < n; i ++ )
41     {
42         int x,y;
43         scanf("%d%d",&x,&y);
44         vv[x].push_back(y);
45         vv[y].push_back(x);
46     }
47     vis[1] = 1;
48     dfs(n,0,1);
49     int k = -1;
50     int s = dep[1] - m;
51     for (int i = 1; i <= n; i ++ ){
52         if(vis[i] && dep[i] == s){
53             k = i;
54             break;
55         }
56     }
57     int num = dep[k] - 1;
58     dfs2(k,f[k],1);
59     ans -- ;
60     num += ans;
61     int r = (num + 1) / 2;
62     int l = 0;
63     while(l < r){
64         int mid = l + r>> 1;
65         int x = min(2 * mid,num);
66         int y = min(mid, ans);
67         if(x - dep[k] + 1>= y) r = mid;
68         else l = mid + 1;
69     }
70     printf("%d\n",l);
71 }
View Code

 

posted @ 2020-08-09 17:53  只能过样例嘤嘤嘤  阅读(208)  评论(0编辑  收藏  举报

……