2019 HDOJ Multi-University Training Contest Stage 4(杭电多校)

很抱歉过了这么多天才补这场,最近真的挺忙的……

出题人是朝鲜的(目测是金策工业?),挺难。

题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=851


A:

签到题。

对于当前的点,若其编号为偶数,则可与1相连使得边权贡献为0。否则从低位向高位找当前点编号的二进制表示的第一个0,使这个0变为1,其他位置变为0并检查新的数字是否小于等于n。若小于等于n则贡献为0,反之贡献为1。

 1 /* basic header */
 2 #include <bits/stdc++.h>
 3 /* define */
 4 #define ll long long
 5 #define dou double
 6 #define pb emplace_back
 7 #define mp make_pair
 8 #define sot(a,b) sort(a+1,a+1+b)
 9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
10 #define rep0(i,a,b) for(int i=a;i<b;++i)
11 #define eps 1e-8
12 #define int_inf 0x3f3f3f3f
13 #define ll_inf 0x7f7f7f7f7f7f7f7f
14 #define lson (curpos<<1)
15 #define rson (curpos<<1|1)
16 /* namespace */
17 using namespace std;
18 /* header end */
19 
20 const int maxn = 2e7;
21 ll bin[60];
22 int ans[maxn];
23 
24 int main() {
25     bin[0] = 1;
26     for (int i = 1; i <= 40; i++) bin[i] = (bin[i - 1] << 1);
27     int T; cin >> T;
28     while (T--) {
29         int n;
30         cin >> n;
31         int sum = 0;
32         for (int i = 1; i <= n; i++) {
33             if (!(i & 1)) {
34                 ans[i] = 1;
35                 continue;
36             }
37             for (int j = 0; j <= 31; j++) {
38                 if ((i & bin[j]) == 0) {
39                     if (bin[j] <= n) ans[i] = bin[j];
40                     else {
41                         ans[i] = 1;
42                         sum++;
43                     }
44                     break;
45                 }
46             }
47         }
48         cout << sum << endl;
49         for (int i = 2; i <= n - 1; i++) cout << ans[i] << " ";
50         cout << ans[n] << endl;
51     }
52     return 0;
53 }
View Code

C:

思维题。参考:https://blog.csdn.net/liufengwei1/article/details/97970041

对于n/k为偶数的情况蛇形填数即可,奇数时只要考虑前3k个,然后剩下就变成了偶数的情况。

 1 /*************************************************************************
 2 *File Name: c.cpp
 3 *Author: JHSeng
 4 *zxc98567@163.com
 5 *Created Time: Sun 11 Aug 2019 12:39:55 AM CST
 6  ************************************************************************/
 7 /* basic header */
 8 #include <bits/stdc++.h>
 9 /* define */
10 #define ll long long
11 #define dou double
12 #define pb emplace_back
13 #define ans make_pair
14 #define sot(a,b) sort(a+1,a+1+b)
15 #define rep1(i,a,b) for(int i=a;i<=b;++i)
16 #define rep0(i,a,b) for(int i=a;i<b;++i)
17 #define eps 1e-8
18 #define int_inf 0x3f3f3f3f
19 #define ll_inf 0x7f7f7f7f7f7f7f7f
20 #define lson (curpos<<1)
21 #define rson (curpos<<1|1)
22 /* namespace */
23 using namespace std;
24 /* header end */
25 
26 int main() {
27     int t; scanf("%d", &t);
28     while (t--) {
29         int n, k; scanf("%d%d", &n, &k);
30         if ((ll)n * (n + 1) / 2 % k || (n == k && n != 1)) {
31             puts("no");
32             continue;
33         }
34         puts("yes");
35         int x = k, y = n / k, ans[x + 5][y + 5];
36         if (y & 1) {
37             for (int i = 1; i <= x; i++) ans[i][1] = i;
38             ans[k / 2 + 1][2] = 2 * k;
39             for (int i = k / 2 + 2; i <= x; i++) ans[i][2] = i - k / 2 - 1 + k;
40             for (int i = 1; i <= k / 2; i++) ans[i][2] = k + k / 2 + i;
41             for (int i = 1; i <= x; i++) ans[i][3] = 4 * k + k / 2 + 2 - ans[i][1] - ans[i][2];
42             int nx = 1, ny = 4;
43             for (int i = 3 * k + 1; i <= n; i++) {
44                 ans[nx][ny] = i;
45                 if (!(ny % 2)) {
46                     if (nx == x) ny++;
47                     else nx++;
48                 } else {
49                     if (nx == 1) ny++;
50                     else nx--;
51                 }
52             }
53         } else {
54             int nx = 1, ny = 1;
55             for (int i = 1; i <= n; i++) {
56                 ans[nx][ny] = i;
57                 if (ny % 2 == 1) {
58                     if (nx == x) ny++;
59                     else nx++;
60                 } else {
61                     if (nx == 1) ny++;
62                     else nx--;
63                 }
64             }
65         }
66         for (int i = 1; i <= x; i++)
67             for (int j = 1; j <= y; j++)
68                 printf("%d%c", ans[i][j], j == y ? '\n' : ' ');
69     }
70     return 0;
71 }
View Code

F:

有一匹马要跳过n棵树,跳过一棵树所消耗的体力等同于树的高度,获得的分数等同于剩余体力。有两种操作:一是在跳一棵树之前把树吃掉,最多m次;二是跳完一棵树之后休息,把体力恢复成已经吃掉的树的高度和,这种操作最多k次。初始体力为0,求最大分数。

休息k次就是把序列分成k+1段,每段贡献分数是负的前缀和的前缀和。考虑吃树,若吃完树之后若在同一段,相当于后面每个位置不用减去这棵树的权值,若不在同一段相当于每个位置会获得这棵树的权值,即分数为a[i]*(n-i+1),这个东西求前m大即可。

显然斜率优化dp。

 1 /* basic header */
 2 #include <bits/stdc++.h>
 3 /* define */
 4 #define ll long long
 5 #define dou double
 6 #define pb emplace_back
 7 #define mp make_pair
 8 #define sot(a,b) sort(a+1,a+1+b)
 9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
10 #define rep0(i,a,b) for(int i=a;i<b;++i)
11 #define eps 1e-8
12 #define int_inf 0x3f3f3f3f
13 #define ll_inf 0x7f7f7f7f7f7f7f7f
14 #define lson (curpos<<1)
15 #define rson (curpos<<1|1)
16 /* namespace */
17 using namespace std;
18 /* header end */
19 
20 const int maxn = 1e4 + 10;
21 ll dp[55][maxn], sum1[maxn], sum2[maxn], score[maxn];
22 int a[maxn];
23 
24 ll X (int i) {return sum1[i];}
25 
26 ll Y(int t, int i) {return dp[t][i] - sum2[i] + i * sum1[i];}
27 
28 int main() {
29     int t; scanf("%d", &t);
30     while (t--) {
31         ll ans = 0;
32         int n, k, m, que[maxn]; scanf("%d%d%d", &n, &k, &m);
33         for (int i = 1; i <= n; i++) {
34             scanf("%d", &a[i]);
35             sum1[i] = sum1[i - 1] + a[i]; sum2[i] = sum2[i - 1] + sum1[i];
36             score[i] = (ll)a[i] * (n - i + 1);
37         }
38         sort(score + 1, score + 1 + n);
39         for (int i = n - m + 1; i <= n; i++) ans += score[i];
40         memset(dp, 0x3f, sizeof(dp)); dp[0][0] = 0;
41         for (int i = 1; i <= k + 1; i++) {
42             int head = 0, tail = 0;
43             que[tail++] = 0;
44             for (int j = 1; j <= n; j++) {
45                 while (head + 1 < tail && (Y(i - 1, que[head + 1]) - Y(i - 1, que[head]) <= j * (X(que[head + 1]) - X(que[head]))))
46                     head++;
47                 dp[i][j] = dp[i - 1][que[head]] + sum2[j] - sum2[que[head]] - (j - que[head]) * sum1[que[head]];
48                 while (head + 1 < tail && (Y(i - 1, que[tail - 1]) - Y(i - 1, que[tail - 2])) * (X(j) - X(que[tail - 1])) >= (Y(i - 1, j) - Y(i - 1, que[tail - 1])) * (X(que[tail - 1]) - X(que[tail - 2])))
49                     tail--;
50                 que[tail++] = j;
51             }
52         }
53         ans -= dp[k + 1][n];
54         printf("%lld\n", ans);
55     }
56     return 0;
57 }
View Code

G:

一开始还以为是反向bfs,白给了两发。

题目说明120步之后就能作判断。可以先比较初始矩阵和目标矩阵数字1、2、3、4的位置,再比较5、6、7、8,以此类推。因为前面的数排完之后就没有后效性了。可以从1*n的矩阵思考,再数学归纳到n*n来思考这个问题。

事实上这是个关于奇数码游戏(就是题目给的游戏)的结论题:奇数码游戏两个局面可达,当且仅当两个局面下网格中的数依次写成一行含有n^2-1个元素的序列中,逆序对个数的奇偶性相同。该结论必要性显然:当空格左右移动时,写成的序列显然不变,不改变逆序对个数奇偶性;空格上下移动时,相当于某个数与它前(或后)边的n-1个数交换了位置,因为n-1是购书,所以逆序对数的变化也只能是偶数。

 1 /* basic header */
 2 #include <bits/stdc++.h>
 3 /* define */
 4 #define ll long long
 5 #define dou double
 6 #define pb emplace_back
 7 #define mp make_pair
 8 #define sot(a,b) sort(a+1,a+1+b)
 9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
10 #define rep0(i,a,b) for(int i=a;i<b;++i)
11 #define eps 1e-8
12 #define int_inf 0x3f3f3f3f
13 #define ll_inf 0x7f7f7f7f7f7f7f7f
14 #define lson (curpos<<1)
15 #define rson (curpos<<1|1)
16 /* namespace */
17 using namespace std;
18 /* header end */
19 
20 const int maxn = 20;
21 
22 int main() {
23     int t; scanf("%d", &t);
24     while (t--) {
25         int ans = 0, a[maxn];
26         rep0(i, 0, 16) {
27             scanf("%d", &a[i]);
28             if (!a[i]) ans += i / 4 + 1 + i % 4 + 1, a[i] = 16;
29             rep1(j, 0, i) if (a[j] > a[i]) ans++;
30         }
31         if (ans & 1) puts("No");
32         else puts("Yes");
33     }
34     return 0;
35 }
View Code

H:

给定一维坐标系上的n个整点和m次询问,每次询问给定L,R,p,K。问在区间[L,R]内到点p距离第K小,输出其距离。

二分答案,看区间[p-ans,p+ans]内有没有k个数。

 1 /* basic header */
 2 #include <bits/stdc++.h>
 3 /* define */
 4 #define ll long long
 5 #define dou double
 6 #define pb emplace_back
 7 #define mp make_pair
 8 #define sot(a,b) sort(a+1,a+1+b)
 9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
10 #define rep0(i,a,b) for(int i=a;i<b;++i)
11 #define eps 1e-8
12 #define int_inf 0x3f3f3f3f
13 #define ll_inf 0x7f7f7f7f7f7f7f7f
14 #define lson (curpos<<1)
15 #define rson (curpos<<1|1)
16 /* namespace */
17 using namespace std;
18 /* header end */
19 
20 const int maxn = 1e6 + 10;
21 int a[maxn], root[maxn], cnt = 0;
22 
23 struct Node {
24     int l, r, sum;
25 } segt[maxn * 40];
26 
27 void update(int pos, int curl, int curr, int &curroot, int &lastroot) {
28     segt[++cnt] = segt[lastroot], segt[cnt].sum++, curroot = cnt;
29     if (curl == curr) return;
30     int mid = curl + curr >> 1;
31     if (pos <= mid) update(pos, curl, mid, segt[curroot].l, segt[lastroot].l);
32     else update(pos, mid + 1, curr, segt[curroot].r, segt[lastroot].r);
33 }
34 
35 int query(int lRoot, int rRoot, int curl, int curr, int ql, int qr) {
36     if (ql <= curl && curr <= qr)
37         return segt[rRoot].sum - segt[lRoot].sum;
38     if (curl == curr) return 0;
39     int mid = curl + curr >> 1;
40     if (qr <= mid) return query(segt[lRoot].l, segt[rRoot].l, curl, mid, ql, qr);
41     else if (ql > mid) return query(segt[lRoot].r, segt[rRoot].r, mid + 1, curr, ql, qr);
42     else return query(segt[lRoot].l, segt[rRoot].l, curl, mid, ql, mid) + query(segt[lRoot].r, segt[rRoot].r, mid + 1, curr, mid + 1, qr);
43 }
44 
45 int main() {
46     int t; scanf("%d", &t);
47     while (t--) {
48         cnt = 0;
49         int n, q, maxx; scanf("%d%d", &n, &q);
50         for (int i = 1; i <= n; i++) {
51             scanf("%d", &a[i]);
52             maxx = max(maxx, a[i]);
53         }
54         for (int i = 1; i <= n; i++)
55             update(a[i], 1, maxx, root[i], root[i - 1]);
56         int lastAns = 0;
57         while (q--) {
58             int l, r, p, k; scanf("%d%d%d%d", &l, &r, &p, &k);
59             l ^= lastAns, r ^= lastAns, p ^= lastAns, k ^= lastAns;
60             int upBound = maxx, lowBound = 0, ans = maxx;
61             while (lowBound <= upBound) {
62                 int mid = lowBound + upBound >> 1;
63                 if (query(root[l - 1], root[r], 1, maxx, p - mid, p + mid) >= k) {
64                     ans = mid;
65                     upBound = mid - 1;
66                 } else lowBound = mid + 1;
67             }
68             lastAns = ans;
69             printf("%d\n", ans);
70         }
71     }
72     return 0;
73 }
View Code

J:

给定正整数n(n>=2),把n唯一分解之后输出最小的幂次。

把n用4000以内的质数分解,然后判断剩下的是否为p2,p3,p4,p2q2的形式即可,若都不是,答案为1。

 1 /* basic header */
 2 #include <bits/stdc++.h>
 3 /* define */
 4 #define ll long long
 5 #define dou double
 6 #define pb emplace_back
 7 #define mp make_pair
 8 #define sot(a,b) sort(a+1,a+1+b)
 9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
10 #define rep0(i,a,b) for(int i=a;i<b;++i)
11 #define eps 1e-8
12 #define int_inf 0x3f3f3f3f
13 #define ll_inf 0x7f7f7f7f7f7f7f7f
14 #define lson (curpos<<1)
15 #define rson (curpos<<1|1)
16 /* namespace */
17 using namespace std;
18 /* header end */
19 
20 const int maxn = 4010;
21 int t, tot, p[maxn], vis[maxn];
22 ll n;
23 
24 void getPrime() {
25     for (int i = 2; i < maxn; i++) {
26         if (!vis[i]) p[tot++] = i;
27         for (int j = 0; j < tot && i * p[j] < maxn; j++) {
28             vis[i * p[j]] = 1;
29             if (i % p[j] == 0) break;
30         }
31     }
32 }
33 
34 int main() {
35     getPrime();
36     int t; scanf("%d", &t);
37     while (t--) {
38         scanf("%lld", &n);
39         int cnt = int_inf, flag = 0;
40         for (int i = 0; i < tot; i++)
41             if (n % p[i] == 0) {
42                 int num = 0;
43                 while (n % p[i] == 0) {
44                     num++; n /= p[i];
45                 }
46                 if (num == 1) flag = 1;
47                 cnt = min(cnt, num);
48             }
49         if (flag) {
50             puts("1");
51             continue;
52         }
53         if (n == 1) {
54             printf("%d\n", cnt);
55             continue;
56         }
57         ll tmp = pow(n, 0.25);
58         if (tmp * tmp * tmp * tmp == n) cnt = min(cnt, 4);
59         else {
60             ++tmp;
61             if (tmp * tmp * tmp * tmp == n) cnt = min(cnt, 4);
62             else {
63                 tmp = pow(n, 0.5);
64                 if (tmp * tmp == n) cnt = min(cnt, 2);
65                 else {
66                     tmp++;
67                     if (tmp * tmp == n) cnt = min(cnt, 2);
68                     else {
69                         tmp = pow(n, 1.0 / 3);
70                         if (tmp * tmp * tmp == n) cnt = min(3, cnt);
71                         else {
72                             tmp++;
73                             if (tmp * tmp * tmp == n) cnt = min(3, cnt);
74                             else cnt = min(1, cnt);
75                         }
76                     }
77                 }
78             }
79         }
80         printf("%d\n", cnt);
81     }
82     return 0;
83 }
View Code

 

转载于:https://www.cnblogs.com/JHSeng/p/11279703.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值