2019 ICPC NanJing Regional Online Contest

比较自闭的一场网络赛,题目质量不错。

题目链接:https://www.jisuanke.com/contest/3004


A:

upsolver: czq

经典的二维偏序问题,求(x,y)左下角点的个数。对x和y升序排序,用树状数组维护每个纵坐标y已经出现的次数,这样就可以动态把点的纵坐标加入树状数组,然后求出比y小的有多少个(树状数组求和)就可以知道当前点的二维偏序值。这道题并不需要离散化,直接开1e6的树状数组即可。

 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 struct Point {
22     int x, y, val, id;
23     Point() {}
24     Point(int a, int b, int c, int d): x(a), y(b), val(c), id(d) {}
25     bool operator<(const Point &rhs)const {
26         return x != rhs.x ? x < rhs.x : y != rhs.y ? y < rhs.y : id < rhs.id;
27     }
28 } p[maxn];
29 
30 int n, m, q, len;
31 ll ans[maxn];
32 
33 struct BIT {
34     int bit[maxn];
35 
36     void init(int n) {
37         rep0(i, 0, n) bit[i] = 0;
38     }
39 
40     int lowbit(int x) {
41         return x & -x;
42     }
43 
44     void add(int pos, int val) {
45         while (pos <= n) {
46             bit[pos] += val;
47             pos += lowbit(pos);
48         }
49     }
50 
51     ll query(int pos) {
52         ll res = 0;
53         while (pos) {
54             res += bit[pos];
55             pos -= lowbit(pos);
56         }
57         return res;
58     }
59 } bit;
60 
61 int getval(int x, int y) {
62     x = n + 1 - x, y = n + 1 - y;
63     ll ans = 0, minn = min(x, min(y, min(n - x + 1, n - y + 1))), ret = 0;
64     ans = x <= y ? minn * (4 * (n - 1) - 4 * minn) + 10 * minn - 4 * n - 3 + x + y : minn * (4 * n - 4 * minn) + 2 * minn + 1 - x - y;
65     while (ans) {
66         ret += ans % 10;
67         ans /= 10;
68     }
69     return ret;
70 }
71 
72 int main() {
73     int t; scanf("%d", &t);
74     while (t--) {
75         scanf("%d%d%d", &n, &m, &q); len = m;
76         bit.init(n);
77         rep1(i, 1, m) {
78             int x, y; scanf("%d%d", &x, &y);
79             p[i] = Point(x, y, getval(x, y), 0);
80         }
81         rep1(i, 1, q) {
82             ans[i] = 0;
83             int x1, x2, y1, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
84             p[++len] = Point(x1 - 1, y1 - 1, 1, i); // when id != 0, means reaching a boarder of rectangle
85             p[++len] = Point(x2, y2, 1, i);
86             p[++len] = Point(x1 - 1, y2, -1, i);
87             p[++len] = Point(x2, y1 - 1, -1, i);
88         }
89         sort(p + 1, p + 1 + len);
90         for (int i = 1; i <= len; i++) //enum each point
91             if (p[i].id) ans[p[i].id] += bit.query(p[i].y) * p[i].val; // if it's a boarder
92             else bit.add(p[i].y, p[i].val); // else add contribution to ans
93         rep1(i, 1, q) printf("%lld
", ans[i]);
94     }
95     return 0;
96 }
View Code

B:

upsolver: rsq

容易猜到答案是a^a^a%mod,因为幂次很高所以要欧拉降幂。队友不知道什么地方写挂了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1111111;
 4 typedef long long ll;
 5 bool check[maxn];
 6 ll phi[maxn];
 7 ll prime[maxn];
 8 ll cnt;
 9 
10 void getphi(ll lim)
11 {
12     phi[1] = 1ll;
13     cnt = 0;
14     check[1] = true;
15     for(ll i = 2;i <= lim;i++){
16         if(!check[i]){
17             prime[++cnt] = i;
18             phi[i] = i-1;
19         }
20         for(ll j = 1ll;j <= cnt;j++){
21             if(i * prime[j] >= lim) break;
22             check[i * prime[j]] = true;
23             if((i % prime[j]) == 0ll){
24                 phi[i * prime[j]] = phi[i] * prime[j];
25                 break;
26             }else {
27                 phi[i * prime[j]] = phi[i] * (prime[j] - 1);
28             }
29         }
30     }
31 }
32 
33 ll getpow(ll a,ll b,ll m)
34 {
35     ll ret = 1ll;
36     ll tmp = a;
37     while(b){
38         if(b&1){
39             ret = ret * tmp;
40             if(ret >= m){
41                 ret = ret % m + m;
42             }
43         }
44         tmp = tmp * tmp;
45         if(tmp >= m){
46             tmp = tmp % m + m;
47         }
48         b >>= 1;
49     }
50     return ret;
51 }
52 
53 ll solve(ll a,ll b,ll m)
54 {
55     if(b == 0ll) return 1ll;
56     if(m == 1) return 1ll;
57     ll pos = solve(a,b-1,phi[m]);
58     return getpow(a,pos,m);
59     
60 }
61 int main(){
62     getphi(1000000);
63     ll T;
64     cin >> T;
65     while(T--){
66         ll a,b,m;
67         cin >> a >> b >> m;
68         cout << solve(a,b,m) % m << endl;            
69     }
70     return 0;
71 }
View Code

F:

solver: zyh, czq

题意很鬼的一题。给定一个全排列,要求构造若干个数列。第i个数列的首个元素必须为i,该序列不上升,该序列中正整数元素在全排列中只能出现一次;对于序列中相邻的元素,若均为正整数,则它们在给定的全排列中的下标只差不能超过给定的正整数k。规定比1小的数只有0。

其实做法还算简单。就是扫一遍全排列,对于每个元素,找区间[i-k,i+k]内的最优解,并看作从i到解连一条有向边;这样,对于出度为0的点,给他们分配一个根节点,就可以弄成一棵树,每个节点的答案就是到根节点的距离-1。

 1 /* Contest nanjing_2019_online
 2  * Problem F
 3  * Team: Make One For Us
 4  */
 5 #include <bits/stdc++.h>
 6 #include <bits/extc++.h>
 7 
 8 using namespace std;
 9 using namespace __gnu_pbds;
10 
11 int arr[100005], ans[100005];
12 
13 int read(void) {
14     char ch;
15     do {
16         ch = getchar();
17     } while (!isdigit(ch));
18     int ret = 0;
19     while (isdigit(ch)) {
20         ret *= 10;
21         ret += ch - '0';
22         ch = getchar();
23     }
24     return ret;
25 }
26 
27 int main(void) {
28     int T;
29     T = read();
30     while (T--) {
31         int n, k;
32         n = read();
33         k = read();
34         for (int i = 0; i < n; i++) {
35             arr[i] = read();
36         }
37         tree <int, null_type, less <int>, rb_tree_tag> ruler;
38         for (int i = 0; i < k; i++) ruler.insert(arr[i]);
39         vector <vector <int>> father(n + 1);
40         for (int i = 0; i < n; i++) {
41             if (i + k < n) ruler.insert(arr[i + k]);
42             if (i - k - 1 >= 0) ruler.erase(arr[i - k - 1]);
43             auto nxt = ruler.lower_bound(arr[i]);
44             if (nxt != ruler.begin()) {
45                 auto val = *--nxt;
46                 father[val].emplace_back(arr[i]);
47             } else father[0].emplace_back(arr[i]);
48         }
49         queue <pair <int, int>> q;
50         q.emplace(make_pair(0, 0));
51         while (!q.empty()) {
52             auto t = q.front();
53             q.pop();
54             ans[t.first] = t.second;
55             for (auto &e : father[t.first]) q.emplace(make_pair(e, t.second + 1));
56         }
57         for (int i = 1; i <= n; i++) printf("%d%c", ans[i], i < n ? ' ' : '
');
58     }
59     return 0;
60 }
View Code

H:

solver: zyh, czq

给定从s到t建边,那么就是从t到s跑6次bellman ford即可。

 1 /* Contest nanjing_2019_online
 2  * Problem H
 3  * Team: Make One For Us
 4  */
 5 #include <bits/stdc++.h>
 6 
 7 using namespace std;
 8 
 9 int n, m;
10 const long long int INF = 1000000000000000LL;
11 
12 struct edge {
13     int u, v;
14     long long int w;
15 };
16 
17 long long int bellman_ford(int s, int t, vector <vector <int>> &g,  vector <edge> &edges) {
18     queue <int> q;
19     vector <long long int> dis(n);
20     vector <bool> inq(n);
21     for (int i = 0; i < n; i++) {
22         dis[i] = INF;
23     }
24     dis[s] = 0;
25     inq[s] = true;
26     q.push(s);
27     while (!q.empty()) {
28         int u = q.front();
29         q.pop();
30         inq[u] = false;
31         for (auto eid : g[u]) {
32             edge &e = edges[eid];
33             if (dis[e.u] < INF && dis[e.v] > dis[e.u] + e.w) {
34                 dis[e.v] = dis[e.u] + e.w;
35                 if (!inq[e.v]) {
36                     q.push(e.v);
37                     inq[e.v] = true;
38                 }
39             }
40         }
41     }
42     return dis[t];
43 }
44 
45 int main(void) {
46     int T;
47     scanf("%d", &T);
48     while (T--) {
49         scanf("%d %d", &n, &m);
50         vector <vector <int>> g(n);
51         vector <edge> edges(m);
52         for (int i = 0; i < m; i++) {
53             scanf("%d %d %lld", &edges[i].u, &edges[i].v, &edges[i].w);
54             g[edges[i].u].emplace_back(i);
55         }
56         for (int i = 0; i < 6; i++) {
57             int s, t;
58             scanf("%d %d", &s, &t);
59             long long int nw = -bellman_ford(t, s, g, edges);
60             printf("%lld
", nw);
61             edges.emplace_back((edge) {
62                 s, t, nw
63             });
64             g[s].emplace_back(m + i);
65         }
66     }
67     return 0;
68 }
View Code
原文地址:https://www.cnblogs.com/JHSeng/p/11443977.html