比较自闭的一场网络赛,题目质量不错。
题目链接:https://www.jisuanke.com/contest/3004
A:
upsolver: czq
经典的二维偏序问题,求(x,y)左下角点的个数。对x和y升序排序,用树状数组维护每个纵坐标y已经出现的次数,这样就可以动态把点的纵坐标加入树状数组,然后求出比y小的有多少个(树状数组求和)就可以知道当前点的二维偏序值。这道题并不需要离散化,直接开1e6的树状数组即可。
1 /* basic header */ 2 #include3 /* 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;i11 #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\n", ans[i]); 94 } 95 return 0; 96 }
B:
upsolver: rsq
容易猜到答案是a^a^a%mod,因为幂次很高所以要欧拉降幂。队友不知道什么地方写挂了。
1 #include2 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 }
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 #include6 #include 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 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 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 ? ' ' : '\n'); 58 } 59 return 0; 60 }
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 #include6 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 int>> &g, vector &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 int>> g(n); 51 vector 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\n", nw); 61 edges.emplace_back((edge) { 62 s, t, nw 63 }); 64 g[s].emplace_back(m + i); 65 } 66 } 67 return 0; 68 }