很抱歉过了这么多天才补这场,最近真的挺忙的……
出题人是朝鲜的(目测是金策工业?),挺难。
题目链接: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 }
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 ? ' ' : ' '); 69 } 70 return 0; 71 }
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 ", ans); 55 } 56 return 0; 57 }
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 }
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 ", ans); 70 } 71 } 72 return 0; 73 }
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 ", 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 ", cnt); 81 } 82 return 0; 83 }