• 2019-2020 ICPC Asia Taipei-Hsinchu Regional Contest 部分题解


    2019-2020 ICPC Asia Taipei-Hsinchu Regional Contest

    A. Rush Hour Puzzle

    队友写的暴搜+剪枝。

    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 2010
    #define mod 998244353
    using namespace std;
    struct cv {
    	int mp[6][6];
    	int mov;
    	friend bool operator<(cv p, cv q) {
    		for (int i = 0; i < 6; i++) {
    			for (int j = 0; j < 6; j++) {
    				if (p.mp[i][j] != q.mp[i][j]) return p.mp[i][j] < q.mp[i][j];
    			}
    		}
    		return p.mp[0][0] < q.mp[0][0];
    	}
    }dd, hf;
    int to[4][2] = { 0,1,0,-1,1,0,-1,0 };
    int main() {
    	for (int i = 0; i < 6; i++) {
    		for (int j = 0; j < 6; j++) {
    			scanf("%d", &dd.mp[i][j]);
    		}
    	}
    	dd.mov = 0;
    	queue<cv>q;
    	q.push(dd);
    	set<cv>st;
    	st.insert(dd);
    	while (!q.empty()) {
    		dd = q.front();
    		q.pop();
    		if (dd.mp[2][5] == 1) {
    			int cnt = 1;
    			for (int i = 4; i >= 0; i--) {
    				if (dd.mp[2][i] != 1) break;
    				cnt++;
    			}
    			int ans = (dd.mov + cnt);
    			if (ans > 10) ans = -1;
    			printf("%d
    ", ans);
    			return 0;
    		}
    		if (dd.mov == 10) break;
    		for (int i = 0; i < 6; i++) {
    			for (int j = 0; j < 6; j++) {
    				if (dd.mp[i][j] == 0) {
    					for (int k = 0; k < 4; k++) {
    						int x = i + to[k][0], y = j + to[k][1];
    						if (x < 0 || x >= 6 || y < 0 || y >= 6 || dd.mp[x][y] == 0) {
    							continue;
    						}
    						int xx = x + to[k][0], yy = y + to[k][1];
    						if (xx < 0 || xx >= 6 || yy < 0 || yy >= 6 || dd.mp[x][y] != dd.mp[xx][yy]) {
    							continue;
    						}
    						while (xx >= 0 && xx < 6 && yy >= 0 && yy < 6 && dd.mp[x][y] == dd.mp[xx][yy]) {
    							xx = xx + to[k][0], yy = yy + to[k][1];
    						}
    						xx = xx - to[k][0], yy = yy - to[k][1];
    						hf = dd;
    						hf.mov++;
    						swap(hf.mp[i][j], hf.mp[xx][yy]);
    						if (!st.count(hf)) {
    							st.insert(hf);
    							q.push(hf);
    						}
    					}
    				}
    			}
    		}
    	}
    	printf("-1
    ");
    	return 0;
    }
    

    C. Are They All Integers?

    题意:给定一个数组 (a_n) ,判断是否所有的三元集 ((i,j,k)) 均满足 (frac{a_i-a_j}{a_k}) 为整数。

    分析(n) 很小,直接暴力。

    #include <bits/stdc++.h>
    using namespace std;
     
    const int maxn = 55;
    int a[maxn];
     
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
     
        bool flag = true;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                for (int k = 1; k <= n; k++)
                    if (i != j && j != k && i != k && (a[i] - a[j]) % a[k])
                        flag = false;
     
        if (flag)
            printf("yes
    ");
        else
            printf("no
    ");
     
        return 0;
    }
    

    D. Tapioka

    签到。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
     
    int main() {
    	io(); string s;
    	bool f = false;
    	for (int i = 1; i <= 3; ++i) {
    		string x; cin >> x;
    		if (x != "bubble" && x != "tapioka") {
    			if (f) s += " ";
    			s += x;
    			f = true;
    		}
    	}
    	if (s == "") s = "nothing";
    	cout << s;
    }
    

    E. The League of Sequence Designers

    队友秒了。

    #include <bits/stdc++.h>
    using namespace std;
     
    int a[2005];
     
    int main()
    {
        int t;
        scanf("%d", &t);
     
        while (t--) {
            int k, len;
            scanf("%d%d", &k, &len);
     
            if (len >= 2000) {
                printf("-1
    ");
                continue;
            }
     
            a[1] = -1;
            int cnt = (1999 + k) % 1998;
            fill(a + 2, a + 2000, (1999 + k) / 1998);
            a[1999] += cnt;
     
            printf("1999
    ");
            for (int i = 1; i <= 1999; i++)
                printf("%d ", a[i]);
            printf("
    ");
        }
     
        return 0;
    }
    

    H. Mining a

    题意:对于一个给定的 (n) 求出最大的正整数 (a) ,满足 (frac{1}{n}=frac{1}{aoplus b}+frac{1}{b}) ,其中 (b) 是一个任意的正整数。

    分析:猜结论,由这个基础的变换 (frac{1}{n}=frac{1}{n}-frac{1}{n+1}+frac{1}{n+1}=frac{1}{n(n+1)}+frac{1}{n+1}) 直接猜 (a=n(n+1)oplus (n+1))

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
     
    int main() {
    	io(); int t;
    	cin >> t;
    	while (t--) {
    		ll n; cin >> n;
    		ll ans = (n * (n + 1ll) ^ (n + 1ll));
    		cout << ans << '
    ';
    	}
    }
    

    J. Automatic Control Machine

    队友秒了。

    #include <bits/stdc++.h>
    using namespace std;
     
    const int maxn = 505;
    char s[maxn];
    bitset<maxn> p[20];
     
    int main()
    {
        int t;
        scanf("%d", &t);
     
        while (t--) {
            int n, m;
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= m; i++) {
                scanf("%s", s + 1);
                p[i].reset();
                for (int j = 1; j <= n; j++)
                    if (s[j] == '1')
                        p[i].set(j);
            }
     
            int base = (1 << m) - 1, ans = 20;
            for (int i = 0; i <= base; i++) {
                bitset<maxn> cnt;
                int k = 0;
                for (int j = 0; j < m; j++)
                    if (i & (1 << j))
                        cnt |= p[j + 1],
                            k++;
                if ((int)cnt.count() == n)
                    ans = min(ans, k);
            }
     
            if (ans == 20)
                printf("-1
    ");
            else
                printf("%d
    ", ans);
        }
     
        return 0;
    }
    

    K. Length of Bundle Rope

    队友秒了。

    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 10010
    #define mod 998244353
    using namespace std;
    
    int main() {
    	int t;
    	scanf("%d", &t);
    	while (t--) {
    		int n;
    		scanf("%d", &n);
    		priority_queue<int, vector<int>, greater<int> >s;
    		for (int i = 0; i < n; i++) {
    			int x;
    			scanf("%d", &x);
    			s.push(x);
    		}
    		int ans = 0;
    		for (int i = 0; i < n - 1; i++) {
    			int x = s.top();
    			s.pop();
    			int y = s.top();
    			s.pop();
    			ans += x + y;
    			s.push(x + y);
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    

    L. Largest Quadrilateral

    题意:给定平面上 (n) 个点,求平面最大四边形。

    分析:显然先把凸包跑出来,最大四边形的顶点必定在凸包上。但是这题非常坑,数据中有重点,并且如果凸包上只有三个点,那么会构成凹四边形。排除这些特判后就是个旋转卡壳了,像求平面最大三角形那样旋转即可,因为四边形可以看作是两个三角形,我们以四边形对角线为这两个三角形的底边,就能写出一个 (O(n^2)) 的旋转卡壳了。

    #define _CRT_SECURE_NO_WARNINGS
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    #pragma comment(linker, "/stack:200000000")
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
    int num;
     
    struct Point {
    	ll x, y;
    	Point() {}
    	Point(ll xx, ll yy) :x(xx), y(yy) {}
    	Point operator + (const Point& k1) const { return Point(k1.x + x, k1.y + y); }
    	Point operator - (const Point& k1) const { return Point(x - k1.x, y - k1.y); }
    	Point operator * (ll k1) const { return Point(x * k1, y * k1); }
    	Point operator / (ll k1) const { return Point(x / k1, y / k1); }
    	bool operator < (const Point& b) const {
    		return (x < b.x) || (x == b.x && y < b.y);
    	}
    	bool operator ==(const Point& b) const {
    		return (x == b.x) && (y == b.y);
    	}
    	ll abs() { return x * x + y * y; }
    	ll dis(Point k1) { return ((*this) - k1).abs(); }
    };
     
    ll cross(Point a, Point b) { return a.x * b.y - a.y * b.x; }	//叉积
    ll dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }	//点积
    ll area(Point a, Point b, Point c) { return abs(cross(a - b, a - c)); }
     
    vector<Point> ConvexHull(vector<Point>A, int flag = 1) { // flag = 0 不严格 flag = 1 严格
    	int n = A.size(); vector<Point>ans(n * 2);
    	sort(A.begin(), A.end()); int now = -1;
    	for (int i = 0; i < A.size(); i++) {
    		while (now > 0 && cross(ans[now] - ans[now - 1], A[i] - ans[now - 1]) < flag) now--;
    		ans[++now] = A[i];
    	}
    	int pre = now;
    	for (int i = n - 2; i >= 0; i--) {
    		while (now > pre&& cross(ans[now] - ans[now - 1], A[i] - ans[now - 1]) < flag) now--;
    		ans[++now] = A[i];
    	}
    	ans.resize(now);
    	return ans;
    }
     
    inline int nxt(int i) { return i == num - 1 ? 0 : i + 1; }
    
    ll Rotating_calipers(int n, vector<Point>& p) {
    	ll ans = 0;
    	for (int i = 0; i < n; i++) {
    		int p1 = nxt(i);
    		int p2 = nxt(nxt(nxt(i)));
    		for (int j = nxt(nxt(i)); nxt(j) != i; j = nxt(j)) {
    			while (nxt(p1) != j && area(p[i], p[nxt(p1)], p[j]) > area(p[i], p[p1], p[j]))
    				p1 = nxt(p1);
    			if (p2 == j) p2 = nxt(p2);
    			while (nxt(p2) != i && area(p[j], p[nxt(p2)], p[i]) > area(p[j], p[p2], p[i]))
    				p2 = nxt(p2);
    			ans = max(ans, area(p[i], p[p1], p[j]) + area(p[j], p[p2], p[i]));
    		}
    	}
    	return ans;
    }
     
    int main() {
    	io(); int t;
    	cin >> t;
    	while (t--) {
    		int n; cin >> n;
    		vector<Point> p(n);
    		for (auto& i : p) cin >> i.x >> i.y;
    		vector<Point> ch = ConvexHull(p, 0);
    		num = ch.size();
    		ll maxs = 0;
    		if (ch.size() < 3) maxs = 0;
    		else if (ch.size() == 3) {
    			ll s = area(ch[0], ch[1], ch[2]);
    			for (auto i : p) {
    				if (i == ch[0] || i == ch[1] || i == ch[2]) continue;
    				ll mins = min(area(i, ch[1], ch[2]), min(area(ch[0], i, ch[2]),
    					area(ch[0], ch[1], i)));
    				maxs = max(maxs, s - mins);
    			}
    		}
    		else maxs = Rotating_calipers(ch.size(), ch);
    		cout << ((maxs & 1ll) ? to_string(maxs / 2ll) + ".5
    " : to_string(maxs / 2ll) + "
    ");
    	}
    }
    

    M. DivModulo

    题意:给定正整数 (N,M,D)(C_M^N dmod {D}) 。其中 (x dmod y) 指的是去掉 (x) 中所有 (y) 因子后取余数,假设 (x=z imes y^k(y mid z)) ,那么 (x dmod y=zmod{y})

    分析:根据表述习惯,我们改写为求解 (C_N^M dmod {D}) 。然后记 (x div y) 为去掉 (x) 中所有 (y) 因子。则有:

    [C^M_N=frac{N!}{M!(N-M)!}=frac{N! div D}{(M! div D) imes ((N-M)! div D)} imes D^K ]

    因此若上式分母与 (D) 互质,则

    [C^M_N dmod D=(N! div D) imes inv(M! div D) imes inv((N-M)! div D)mod{D} ]

    其中 (inv) 表示模 (D) 的逆元,这个问题只需要简单的分段就能解决了。

    若上式分母与 (D) 不互质,我们先将 (D) 的质因子分解:(D=D_1D_2cdots D_s=p_1^{a_1}p_2^{a_2}cdots p_s^{a_s}) ,其中 (p_i) 为质因子。于是可以推出:

    [C_M^N=frac{N! div p_i}{(M! div p_i) imes ((N-M)! div p_i)} imes p_i^{k_i} ]

    因此我们可以得到 (K=underset{iin[1,s]}{min{frac{k_i}{a_i}}}) ,然后推出:

    [C^M_N div Dequiv frac{C^M_N}{D^K}equiv frac{(C^M_N div p_i) imes p_i^{k_i}}{D^K}equivfrac{(C^M_N div p_i) imes p_i^{k_i-Ka_i}}{(frac{D}{D_i})^K}mod{D_i} ]

    由上式,我们对于所有 (iin[1,s]) 都能求出 (C^M_N div Dmod{D_i}) 的值,因为该式中分母与模数互质,逆元存在,然后就能通过扩展中国剩余定理求出 (C^M_N div Dmod{D})

    那么最后还剩下一个问题,怎么求 (C^M_N div Dmod{D_i}) ,该问题等价于求 (N! div Dmod{P})

    我们将 (N!) 分成两部分考虑:(N!=underset{Dmid i}{prod^N_{i=1}}{i} imes underset{D mid i}{prod^N_{i=1}}{i}) ,即把能整除 (D)(i) 分为一类,不能整除的分为一类。

    [N!=underset{Dmid i}{prod^N_{i=1}}{i} imes underset{D mid i}{prod^N_{i=1}}{i}=(D^{lfloor frac{N}{D} floor} imes lfloor frac{N}{D} floor !) imes ((underset{D mid i}{prod^P_{i=1}}{i})^{lfloor frac{N}{P} floor} imes(underset{D mid i}{prod^{P\%N}_{i=1}}{i})) ]

    因此:(N! div Dmod{P}=lfloor frac{N}{D} floor ! imes (underset{D mid i}{prod^P_{i=1}}{i})^{lfloor frac{N}{P} floor} imesunderset{D mid i}{prod^{P\%N}_{i=1}}{i}mod{P})

    观察该式不难发现,对于 ((underset{D mid i}{prod^P_{i=1}}{i})^{lfloor frac{N}{P} floor} imesunderset{D mid i}{prod^{P\%N}_{i=1}}{i}mod{P}) 这部分的值,我们只需要 (O(P)) 的预处理后就能 (O(1)) 查询,然后 (N!) 每次都能够转化为 (lfloor frac{N}{D} floor !) 的子问题。由于 (Dleq1.6e7) ,我们可以计算出任意一个 (1.6e7) 以内的数字最多含有 (8) 个质因子,因此粗略地估计一下,复杂度上限为 (O(8(D+log_{D}{N}))) ,当然不可能达到这个复杂度。

    #define _CRT_SECURE_NO_WARNINGS
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    #pragma comment(linker, "/stack:200000000")
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
    ll M, N, D, ans;
    
    namespace Pollard_Rho {
    	map<ll, ll> MP;
    	inline ll gcd(ll a, ll b) {
    		return b == 0 ? a : gcd(b, a % b);
    	}
    	inline ll mulmod(ll x, ll y, const ll z) {
    		return (x * y - (ll)(((long double)x * y + 0.5) / (long double)z) * z + z) % z;
    	}
    	inline ll powmod(ll a, ll b, const ll mo) {
    		ll s = 1;
    		for (; b; b >>= 1, a = mulmod(a, a, mo)) if (b & 1) s = mulmod(s, a, mo);
    		return s;
    	}
    	bool isPrime(ll p) { // Miller-Rabin
    		const int lena = 10, a[lena] = { 2,3,5,7,11,13,17,19,23,29 };
    		if (p == 2) return true;
    		if (p == 1 || !(p & 1) || (p == 46856248255981ll)) return false;
    		ll D = p - 1; while (!(D & 1)) D >>= 1;
    		for (int i = 0; i < lena && a[i] < p; i++) {
    			ll d = D, t = powmod(a[i], d, p); if (t == 1) continue;
    			for (; d != p - 1 && t != p - 1; d <<= 1) t = mulmod(t, t, p);
    			if (d == p - 1) return false;
    		}
    		return true;
    	}
    	void reportFactor(ll n) { // 得到一个素因子
    		MP.count(n);
    		MP[n]++;
    	}
    	ll ran() { return rand(); } // 随机数
    	void getFactor(ll n) { // Pollard-Rho
    		if (n == 1) return;
    		if (isPrime(n)) { reportFactor(n); return; }
    		while (true) {
    			ll c = ran() % n, i = 1, x = ran() % n, y = x, k = 2;
    			do {
    				ll d = gcd(n + y - x, n);
    				if (d != 1 && d != n) { getFactor(d); getFactor(n / d); return; }
    				if (++i == k) y = x, k <<= 1;
    				x = (mulmod(x, x, n) + c) % n;
    			} while (y != x);
    		}
    	}
    }
    using namespace Pollard_Rho;
    
    void exgcd(ll a, ll b, ll& x, ll& y) {
    	if (!b) x = 1, y = 0;
    	else exgcd(b, a % b, y, x), y -= a / b * x;
    }
    
    ll qpow(ll a, ll b, ll mod) {
    	ll ans = 1;
    	while (b) {
    		if (b & 1) ans = (ans * a) % mod;
    		a = (a * a) % mod;
    		b >>= 1;
    	}
    	return ans;
    }
    
    ll calc_divs(ll m, ll mod) {
    	ll ans = 0;
    	for (ll i = mod; ; i *= mod) {
    		ans += m / i;
    		if ((long double)i * mod > m) return ans;
    	}
    }
    
    ll calc_fac(ll p, ll mod, vector<ll>& fac) {
    	if (p == 0) return 1;
    	return calc_fac(p / mod, mod, fac) * qpow(fac[mod - 1], p / mod, mod) % mod * fac[p % mod] % mod;
    }
    
    ll getinv(ll n, ll mod) {
    	ll x, y;
    	exgcd(n, mod, x, y);
    	return (x + mod) % mod;
    }
    
    ll excrt(ll a, ll m, ll b, ll n) {
    	ll x, y; exgcd(m, n, x, y);
    	ll ret = a * (y + m) % m * n + b * (x + n) % n * m;
    	if (ret >= m * n) ret -= m * n;
    	return ret;
    }
    
    int main() {
    	io(); cin >> N >> M >> D;
    	getFactor(D);
    	vector<ll> ki;
    	ll K = 1e18;
    	for (auto it : MP) {
    		ll p = it.first;
    		ki.emplace_back(calc_divs(N, p) - calc_divs(M, p) - calc_divs(N - M, p));
    		K = min(ki.back() / it.second, K);
    	}
    
    	int cnt = 0;
    	ll fmod = 1;
    	for (auto it : MP) {
    		ll p = it.first, a = it.second;
    		ll cur = qpow(p, a, (ll)1e18);
    		ll divs = ki[cnt] - K * a;
    		vector<ll> val(cur);
    		vector<ll> fac(cur);
    
    		for (int i = 1; i < cur; ++i) val[i] = i;
    		for (ll i = p; i * p <= cur; i *= p)
    			for (ll j = i; j < cur; j += i)
    				val[j] /= p;
    		val[0] = fac[0] = 1;
    		for (int i = 1; i < cur; ++i) fac[i] = fac[i - 1] * val[i] % cur;
    		ll res = calc_fac(N, cur, fac) * getinv(calc_fac(M, cur, fac), cur) % cur
    			* getinv(calc_fac(N - M, cur, fac), cur) % cur
    			* getinv(qpow(D / cur, K, cur), cur) % cur;
    		ans = excrt(ans, fmod, res * qpow(p, divs, cur) % cur, cur);
    		fmod *= cur;
    		++cnt;
    	}
    	cout << ans;
    }
    
  • 相关阅读:
    发现CSDN的一个小Bug,CSDN网站管理人员进来看看哈~~
    “凡客好声音”摇滚派对专场 正火热抢票中!
    帧动画
    java WEB Response重定向和缓存控制
    上一篇括号配对让人联想起catalan数,顺便转载一篇归纳的还不错的文章
    字符串循环移位
    应用层协议实现系列(三)——FTPserver之设计与实现
    HDU1575-Tr A(矩阵高速幂)
    音视频即时通讯的分包与重组
    怎样批量重命名照片,可是去掉那个烦人的括号
  • 原文地址:https://www.cnblogs.com/st1vdy/p/12701920.html
Copyright © 2020-2023  润新知