5/5
好久没写博客了,难得有空写个题解,难得有空补不动~~
题A hdu5776 sum
题意:略
题解:dp[x]表示前缀modm的余数有没有出现,如果同一个结果出现两次,那么就说明中间的一段是可以整除m的,当然不要忘了本身前缀就能够整除。
1 /*zhen hao*/
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5 #include <queue>
6 #include <vector>
7 #include <string>
8 #include <stack>
9 #include <set>
10 #include <map>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14
15 #define lson l, m, rt*2
16 #define rson m + 1, r, rt*2+1
17 #define xx first
18 #define yy second
19
20 typedef pair<int,int> pii;
21 typedef long long ll;
22 typedef unsigned long long ull;
23
24 const int N = 5e3 + 10;
25 int dp[N];
26
27 int main() {
28 // freopen("case.in", "r", stdin);
29
30 int T;
31 cin >> T;
32 while (T--) {
33 memset(dp, 0, sizeof dp);
34 int n, m, now = 0, ok = 0;
35 scanf("%d%d", &n, &m);
36 for (int i = 0; i < n; i++) {
37 int x;
38 scanf("%d", &x);
39 now = (now + x) % m;
40 if (now == 0 || dp[now]) ok = 1;
41 dp[now] = 1;
42 }
43 if (ok) puts("YES"); else puts("NO");
44 }
45
46 }
题B hdu5777 domino
题意:略
题解:仔细观察发现贪心可解,sort一下即可。
1 /*zhen hao*/
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5 #include <queue>
6 #include <vector>
7 #include <string>
8 #include <stack>
9 #include <set>
10 #include <map>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14
15 #define lson l, m, rt*2
16 #define rson m + 1, r, rt*2+1
17 #define xx first
18 #define yy second
19
20 typedef pair<int,int> pii;
21 typedef long long ll;
22 typedef unsigned long long ull;
23
24 const int N = 1e5 + 10;
25 int d[N];
26
27 int main() {
28 // freopen("case.in", "r", stdin);
29
30 int T;
31 cin >> T;
32 while (T--) {
33 int n, k;
34 scanf("%d%d", &n, &k);
35 for (int i = 0; i < n - 1; i++) {
36 scanf("%d", d + i);
37 }
38 sort(d, d + n - 1, greater<int>());
39 ll sum = 0;
40 for (int i = k - 1; i < n - 1; i++) {
41 sum = sum + d[i];
42 }
43 printf("%I64d
", sum + n);
44 }
45
46 }
题C hdu5778 abs
题意:略
题解:质因子都是2说明这个数一定是平方数,然后对于x,我们先把它去个根的sx,然后我们枚举距离这个sx最近的距离d,然后判断d的质因子是不是都是一个。还有一个问题,我们取得这个sx可能sx+1更优,所以要先判断一下哪个距离x更近。
1 /*zhen hao*/
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5 #include <queue>
6 #include <vector>
7 #include <string>
8 #include <stack>
9 #include <set>
10 #include <map>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14
15 #define lson l, m, rt*2
16 #define rson m + 1, r, rt*2+1
17 #define xx first
18 #define yy second
19
20 typedef pair<int,int> pii;
21 typedef long long ll;
22 typedef unsigned long long ull;
23
24 const int N = 1e5 + 10;
25 bool vis[N];
26 vector<int> p;
27
28 void init() {
29 for (int i = 2; i < N; i++) if (!vis[i])
30 for (int j = i + i; j < N; j += i) vis[j] = 1;
31 for (int i = 2; i < N; i++) if (!vis[i]) p.push_back(i);
32 }
33
34 bool check(ll n) {
35 if (n < 2) return false;
36 int m = (int)sqrt(n + 0.5);
37 for (int i = 0; i < (int)p.size() && p[i] <= m; i++) if (n % p[i] == 0) {
38 int c = 0;
39 while (n % p[i] == 0) {
40 n /= p[i];
41 c++;
42 }
43 if (c > 1) return false;
44 }
45 return true;
46 }
47
48 int main() {
49 // freopen("case.in", "r", stdin);
50
51 init();
52 int T;
53 cin >> T;
54 while (T--) {
55 ll x;
56 scanf("%I64d", &x);
57 ll sx = (ll)sqrt(x + 0.5);
58 if (abs(sx * sx - x) > abs((sx + 1) * (sx + 1) - x)) ++sx;
59 int d = 0;
60 while (true) {
61 if (check(sx + d)) break;
62 if (check(sx - d)) break;
63 d++;
64 }
65 ll res = 1e18;
66 if (check(sx + d)) res = min(res, abs(x - (sx + d) * (sx + d)));
67 if (check(sx - d)) res = min(res, abs(x - (sx - d) * (sx - d)));
68 cout << res << endl;
69 }
70
71 }
题D 5779 Tower Defence
题意:略
题解:太弱了,第一眼看不到题解的状态转移,实际上题解的状态转移描述得已经够专业了。但是我是结合代码才看得懂(/▽╲)!!这里详细地解释一下怎么转移的吧,毕竟都把代码看懂了。
题目说最短路不是k,很容易由反证法得到这个最短路是小于k的。
先定义一个状态数组,f(i,j,k)表示与1连接的那个连通块(包括1)的size,当前的最短路是j,得到这个最短路的点数是k。
我们发现如果想要最短路的长度加一,那么必须是从非连通块里面的点连到这k个点的其中x个(1 <= x <= k),所以我们要枚举接下来的连通块以外的新点的个数x,目的是更新状态f(i+x,j+1,x)。
转移:(假设上一层是k个点,下一层是x个点)
(1)对于第二层的每个点x,从第一层的k个点里面人选1到k个连边,方法数是2 ^ k - 1。
(2)对于第二层的每个点x自己互相连边,方案数是2 ^ (x * (x - 1) / 2),因为共有这么条边,可以连也可以不连
(3)这个最难想,因为我们增加了x个点,那么原来图中有多少个点是可以换位置的呢?答案就是非1和非最短路为j的点,所以由i - k - 1个点里面选x作为最短路为j+1的点。
这三步我们得到了f(i,j,k)。
给定n和k怎么得到答案呢?枚举与1连通的点,然后剩余的点可以乱排,同样要考虑排列组合。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define xx first
8 #define yy second
9
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13
14 const int N = 61, mod = 1e9 + 7;
15 ll f[N][N][N], C[N][N], p2[N * N], p2_1[N];
16
17 void add(ll& a, ll b) {
18 a += b;
19 if (a >= mod) a -= mod;
20 }
21
22 void init() {
23 for (int i = 0; i < N; i++) {
24 C[i][0] = 1;
25 for (int j = 1; j <= i; j++)
26 add(C[i][j], (C[i - 1][j] + C[i - 1][j - 1]) % mod);
27 }
28 // cout << C[5][3] << endl;
29 p2[0] = p2_1[0] = 1;
30 for (int i = 1; i < N * N; i++) p2[i] = p2[i - 1] * 2 % mod;
31 for (int i = 1; i < N; i++) p2_1[i] = (p2[i] + mod - 1) % mod;
32 // cout << p2[5] << ' ' << p2_1[5] << endl;
33 f[1][0][1] = 1;
34 for (int i = 1; i < N; i++)
35 for (int j = 0; j < i; j++)
36 for (int k = 1; k <= i; k++) if (f[i][j][k]) {
37 ll tmp = f[i][j][k];
38 for (int l = 1; l + i < N; l++) {
39 tmp = tmp * p2_1[k] % mod;
40 ll val = tmp;
41 val = val * p2[l * (l - 1) / 2] % mod;
42 val = val * C[i + l - 1][l] % mod;
43 add(f[i + l][j + 1][l], val);
44 }
45 }
46 }
47
48 ll get_ans(int n, int k) {
49 ll ans = 0;
50 for (int i = 1; i <= n; i++)
51 for (int j = 0; j < k; j++)
52 for (int l = 1; l <= i; l++) if (f[i][j][l]) {
53 ll tmp = f[i][j][l];
54 tmp = tmp * C[n - 1][n - i] % mod;
55 tmp = tmp * p2[(n - i) * (n - i - 1) / 2] % mod;
56 add(ans, tmp);
57 }
58 return ans;
59 }
60
61 int main() {
62 // freopen("case.in", "r", stdin);
63
64 init();
65 int T;
66 cin >> T;
67 while (T--) {
68 int n, k;
69 cin >> n >> k;
70 cout << get_ans(n, k) << '
';
71 }
72
73 return 0;
74 }
题E hdu5780 gcd
题意:略
题解:实际上官方题解已经写得很详细了,我再复述有点多余(/▽╲)改天有空补上这个公式证明吧,希望我不会忘记。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define xx first
8 #define yy second
9
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13
14 const int N = 1e6, mod = 1e9 + 7;
15 int phi[N + 10];
16 ll s[N + 10];
17
18 void phi_table() {
19 phi[1] = 1;
20 for (int i = 2; i <= N; i++) if (!phi[i])
21 for (int j = i; j <= N; j += i) {
22 if (!phi[j]) phi[j] = j;
23 phi[j] = phi[j] / i * (i - 1);
24 }
25 for (int i = 1; i <= N; i++)
26 s[i] = (s[i - 1] + phi[i]) % mod;
27 }
28
29 ll quick(ll a, ll b, ll c) {
30 ll ret = 1;
31 while (b > 0) {
32 if (b & 1) ret = ret * a % c;
33 b = b / 2;
34 a = a * a % c;
35 }
36 return ret;
37 }
38
39 ll get_ans(int x, int n) {
40 if (x == 1) return 0ll;
41 ll ret = 0;
42 ll inv = quick(x - 1, mod - 2, mod);
43 for (int i = 1, j; i <= n; i = j + 1) {
44 j = n / (n / i);
45 ll sd = 2ll * s[n / i] - 1;
46 ll a0 = quick(x, i, mod), qn = quick(x, j - i + 1, mod) + mod - 1;
47 ll tmp = a0 * qn % mod;
48 tmp = tmp * inv % mod;
49 tmp = (tmp + mod - (j - i + 1)) % mod;
50 tmp = sd * tmp % mod;
51 ret += tmp;
52 if (ret >= mod) ret -= mod;
53 }
54 return ret;
55 }
56
57 int main() {
58 // freopen("case.in", "r", stdin);
59
60 phi_table();
61 int T;
62 cin >> T;
63 while (T--) {
64 int x, n;
65 scanf("%d%d", &x, &n);
66 cout << get_ans(x, n) << endl;
67 }
68
69 return 0;
70 }