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

今天究极自闭……继续锅++

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


A:

凸包+区间dp。

B:

图论题。

C:

点分治。给一个参考博客:https://www.cnblogs.com/uid001/p/11266021.html

D:

题目令最大值最小,显然可以直接二分答案。

设每次答案为x,如何判定x能否满足分为k份的要求?考虑dp。

令dp[i]表示前i个数最多能分为几段,则有:

dp[i]=max(dp[j])+1; (若sum[i]-sum[j]<=x)

直接dp是O(n^2)复杂度,无法接受。可以考虑离散化后权值线段树维护,复杂度降至O(nlogn)。

  1 /*************************************************************************
  2 *File Name: d.cpp
  3 *Author: JHSeng
  4 *zxc98567@163.com
  5 *Created Time: Tue 30 Jul 2019 12:35:56 PM 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 mp 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 const int maxn = 2e5 + 10;
 27 vector<ll>v;
 28 struct Node {
 29     ll w = 0;
 30 } segt[maxn << 2];
 31 ll a[maxn], sum[maxn];
 32 int n, m, k;
 33 
 34 void build(int curpos, int curl, int curr) {
 35     if (curl == curr) {
 36         segt[curpos].w = 0;
 37         return;
 38     }
 39     int mid = curl + curr >> 1;
 40     build(lson, curl, mid); build(rson, mid + 1, curr);
 41     segt[curpos].w = 0;
 42 }
 43 
 44 void update(int curpos, int pos, int curl, int curr, ll x) {
 45     if (curl == curr) {
 46         segt[curpos].w = max(segt[curpos].w, x);
 47         return;
 48     }
 49     int mid = curl + curr >> 1;
 50     if (pos <= mid) update(lson, pos, curl, mid, x);
 51     else update(rson, pos, mid + 1, curr, x);
 52     segt[curpos].w = max(segt[lson].w, segt[rson].w);
 53 }
 54 
 55 ll query(int curpos, int curl, int curr, int ql, int qr) {
 56     if (ql <= curl && curr <= qr)
 57         return segt[curpos].w;
 58     int mid = curl + curr >> 1; ll ret = 0;
 59     if (ql <= mid) ret = max(ret, query(lson, curl, mid, ql, qr));
 60     if (qr > mid) ret = max(ret, query(rson, mid + 1, curr, ql, qr));
 61     return ret;
 62 }
 63 
 64 int check(ll x) {
 65     build(1, 1, m);
 66     rep1(i, 1, n) {
 67         ll l = lower_bound(v.begin(), v.end(), sum[i] - x) - v.begin() + 1;
 68         ll r = lower_bound(v.begin(), v.end(), sum[i]) - v.begin() + 1;
 69         if (l > m) {
 70             if (sum[i] <= x) update(1, r, 1, m, 1);
 71             continue;
 72         }
 73         ll w = query(1, 1, m, l, m);
 74         if (w) update(1, r, 1, m, w + 1);
 75         else if (sum[i] <= x) update(1, r, 1, m, 1);
 76     }
 77     return query(1, 1, m, 1, m) >= k;
 78 }
 79 
 80 int main() {
 81     sum[0] = 0;
 82     int t; scanf("%d", &t);
 83     while (t--) {
 84         scanf("%d%d", &n, &k);
 85         v.clear();
 86         rep1(i, 1, n) {
 87             scanf("%lld", &a[i]);
 88             sum[i] = sum[i - 1] + a[i];
 89             v.pb(sum[i]);
 90         }
 91         sort(v.begin(), v.end());
 92         v.erase(unique(v.begin(), v.end()), v.end());
 93         m = v.size();
 94         ll l = -1e14 - 10, r = 1e14 + 10, ans = 0;
 95         while (l <= r) {
 96             ll mid = l + r >> 1;
 97             if (check(mid)) {
 98                 ans = mid, r = mid - 1;
 99             } else l = mid + 1;
100         }
101         printf("%lld
", ans);
102     }
103     return 0;
104 }
View Code

参考 https://www.cnblogs.com/inctry/p/11267516.html

E:

一点都不简单的筛式子题。

F:

由质数的密度分布,很明显可以直接暴力找出最大的比p小的质数q。相差不会很远。

如何求大数阶乘呢?用威尔逊定理即可。

 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 ll mulmod(ll x, ll y, ll mod) {
21     ll ret = 0; x %= mod; y %= mod;
22     while (y) {
23         if (y & 1) ret = (ret + x) % mod;
24         x = (x << 1) % mod;
25         y >>= 1;
26     }
27     return ret;
28 }
29 
30 ll qmul(ll x, ll y, ll p) {
31     if (!y) return 1;
32     ll tmp = x, ret = 1;
33     while (y) {
34         if (y & 1) ret = mulmod(ret, tmp, p);
35         tmp = mulmod(tmp, tmp, p);
36         y = y >> 1;
37     }
38     return ret;
39 }
40 
41 int MillerRobin(ll x) {
42     if (x <= 1 || !(x & 1)) return 0;
43     if (x == 2) return 1;
44     rep1(i, 1, 8) {
45         ll rnd = rand() % (x - 2) + 2, k = x - 1;
46         while (!(k & 1)) k >>= 1;
47         ll tmp = qmul(rnd, k, x);
48         while (k != x - 1 && tmp != x - 1 && tmp != 1) {
49             tmp = mulmod(tmp, tmp, x);
50             k <<= 1;
51         }
52         if ((tmp == 1 && !(k & 1)) ||  (tmp == x - 1 && k == x - 1) || (tmp != x - 1 && tmp != 1)) return 0;
53     }
54     return 1;
55 }
56 
57 ll qp(ll a, ll b, ll mod) {
58     ll ret = 1, base = a;
59     while (b) {
60         if (b & 1) ret = mulmod(ret, base, mod);
61         base = mulmod(base, base, mod);
62         b >>= 1;
63     }
64     return ret;
65 }
66 
67 int main() {
68     int t; scanf("%d", &t);
69     while (t--) {
70         ll n, currPrime; scanf("%lld", &n);
71         for (ll i = n - 1; i >= 1; i--) {
72             if (MillerRobin(i)) {
73                 currPrime = i; break;
74             }
75         }
76         ll ans = n - 1;
77         for (ll i = currPrime + 1; i < n; i++) ans = mulmod(ans, qp(i, n - 2, n), n);
78         printf("%lld
", ans);
79     }
80 }
View Code

G:

对于第i个位置,如何选择数字才能在满足条件情况下使得选择数字数目最少?显然是贪心找尽量大的数字。但如果暴力必TLE。

题目可以转化为前i-1个数中最多选出多少个数字和a[i]相加使得其和<=m,显然可以用线段树做。

对给定数组离散化,然后在离散化后的数组建立线段树,线段树上节点记录区间和以及区间内数字个数。

询问时二分出区间第k大即可。时间复杂度O(nlogn)。

 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 = 2e5 + 10;
21 int t, n, ans[maxn];
22 ll m, sum[maxn * 5], cnt[maxn * 5];
23 
24 struct SegmentTree {
25     struct STNode {
26         ll sum, cnt;
27     } mem[maxn * 5];
28 
29     SegmentTree() {
30         rep0(i, 0, maxn * 5) mem[i].cnt = mem[i].sum = 0;
31     }
32 
33     int query(int curpos, int curl, int curr, ll val, ll tot) {
34         if (mem[curpos].sum + tot <= val) return mem[curpos].cnt;
35         int mid = curl + curr >> 1;
36         int ret = query(lson, curl, mid, val, tot);
37         if (ret == mem[lson].cnt)
38             ret += query(rson, mid + 1, curr, val, tot + mem[lson].sum);
39         return ret;
40     }
41 
42     void insert(int curpos, int pos, int curl, int curr, ll val) {
43         if (curl == curr) {
44             mem[curpos].sum = val; mem[curpos].cnt = 1;
45             return;
46         }
47         int mid = curl + curr >> 1;
48         if (pos <= mid) insert(lson, pos, curl, mid, val);
49         else insert(rson, pos, mid + 1, curr, val);
50         mem[curpos].sum = mem[lson].sum + mem[rson].sum;
51         mem[curpos].cnt = mem[lson].cnt + mem[rson].cnt;
52     }
53 
54     void clear() {
55         rep0(i, 0, maxn * 5) mem[i].cnt = mem[i].sum = 0;
56     }
57 } st;
58 
59 struct Node {
60     ll val;
61     int num, rank;
62 } a[maxn];
63 
64 bool cmp(const Node &lhs, const Node &rhs) {
65     return lhs.val < rhs.val;
66 }
67 
68 bool cmp2(const Node &lhs, const Node &rhs) {
69     return lhs.num < rhs.num;
70 }
71 
72 int main() {
73     scanf("%d", &t);
74     while (t--) {
75         st.clear();
76         rep0(i, 0, maxn) ans[i] = 0;
77         scanf("%d%lld", &n, &m);
78         rep1(i, 1, n) {
79             scanf("%lld", &a[i].val);
80             a[i].num = i;
81         }
82         sort(a + 1, a + 1 + n, cmp);
83         rep1(i, 1, n) a[i].rank = i;
84         sort(a + 1, a + 1 + n, cmp2);
85         rep1(i, 1, n) {
86             int t = st.query(1, 1, n, m - a[i].val, 0);
87             ans[i] = i - 1 - t;
88             st.insert(1, a[i].rank, 1, n, a[i].val);
89         }
90         rep1(i, 1, n) printf("%d ", ans[i]);
91         puts("");
92     }
93     return 0;
94 }
View Code

参考 https://www.cnblogs.com/worcher/p/11271148.html

H:

对序列求前缀异或和。修改操作相当于对前缀异或和的单点修改,查询相当于询问区间相同点对数。

三维莫队。

I:

网络流。

J:

差分+线段树+树链剖分。

K:

图论题。

原文地址:https://www.cnblogs.com/JHSeng/p/11267421.html