2021-06-22 集訓題解
阿新 • • 發佈:2021-06-22
T1 戰神歸來
Description
Solution
可以大膽猜測,答案一定是可以取得下界的,下界隨便亂算就好了。
考慮如何構造最優。可以想到的是,加入我們把終點座標>=起點座標的路徑叫做右卡,反之叫做左卡,那麼能讓答案變小的操作一定是在某個交點處交換了地鐵卡,而且最優情況一定是在端點處。可以想到的是,對於一個右卡,如果可以讓他變優,肯定是選左端點儘可能靠左的左卡。
需要注意的是,並不一定交換之後直接結束,還可以繼續操作。
Code
#include <bits/stdc++.h> using namespace std; #define IT multiset<int>::iterator #define Int register int #define ll long long #define MAXN 100005 template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;} template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);} template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> void chkmax (T &a,T b){a = max (a,b);} template <typename T> void chkmin (T &a,T b){a = min (a,b);} int T,n,m; struct node{ int l,r,id; bool operator < (const node &p)const{ return l != p.l ? l < p.l : r < p.r; } }; vector <node> prog; multiset <node> S[2]; void makeit (node A,node B,int p){//在p點匯合並進行交換,A是右卡,B是左卡 if (A.l ^ p) prog.push_back (node{A.id,p,0}); if (B.r + 1 ^ p) prog.push_back (node {B.id,p,0}); prog.push_back (node{A.id,B.id,1}); } void Solveit (ll &ans){ if (S[0].empty() || S[1].empty()) return ; node A = *S[0].begin(),B = *S[1].begin(); if (A.r < B.l) S[0].erase (S[0].begin()),Solveit (ans); else if (B.r < A.l) S[1].erase (S[1].begin()),Solveit (ans); else{ S[0].erase (S[0].begin()),S[1].erase (S[1].begin()); int maxl = max (A.l,B.l),minr = min (A.r,B.r); ans -= minr - maxl + 1 << 1; if (A.r <= B.r){ if (A.r < B.r) S[1].insert (node{A.r + 1,B.r,B.id}); Solveit (ans),makeit (A,B,A.r + 1); } else{ if (B.r < A.r) S[0].insert (node{B.r + 1,A.r,A.id}); makeit (A,B,B.r + 1),Solveit (ans); } } } int ed[MAXN],s[MAXN],t[MAXN]; signed main(){ freopen( "subway.in", "r", stdin ); freopen( "subway.out", "w", stdout ); read (T); while (T --> 0){ read (n,m),S[0].clear (),S[1].clear (),prog.clear(); ll ans = 0; for (Int i = 1;i <= n;++ i){ read (s[i],t[i]),ed[i] = s[i]; if (s[i] < t[i]) ans += t[i] - s[i],S[0].insert (node {s[i],t[i] - 1,i}); else ans += s[i] - t[i],S[1].insert (node {t[i],s[i] - 1,i}); } Solveit (ans); write (ans),putchar (' '); for (auto p : prog) if (!p.id) ed[p.l] = p.r; for (Int i = 1;i <= n;++ i) if (ed[i] ^ t[i]) prog.push_back (node {i,t[i],0}); write (prog.size()),putchar ('\n'); for (Int i = 0;i < prog.size();++ i) write (prog[i].id),putchar (' '),write (prog[i].l),putchar (' '),write (prog[i].r),putchar ('\n'); } return 0; }
T2 組合數問題
Description
Solution
不難看出,答案就是:
\[\sum_{i=0}^{n} i!\times i^m\times (-1)^i \]T3 三角形
Description
\(n\le 5\times 10^9\)
Solution
根據皮克定理
我們可以得到,當且僅當三角形面積為 \(\frac{1}{2}\) 時合法,然後你通過分析可以得出,當且僅當三角形的 邊與 \(x,y\) 軸平行的外接長方形 兩邊長度互質 且 有兩個端點在頂點上成立,所以我們可以得出:
\[\text{ans}=4\sum_{i=1}^{n}\sum_{j=1}^{m} (n-i)\times (m-j)\times [\gcd(i,j)=1] \]然後你反演一下再杜教篩一下就好了。
具體分析如下: