• XIX Open Cup, Grand Prix of SPb【杂题】


    啊哈,好像学会开火车了

    感觉单人 vp ACM 有点自闭,但是没人陪我训练所以没办法了

    G Least Number

    给定正整数 (n) 和数字 (d),求最小的数字和为 (n) 且不含数字 (d) 的正整数。

    (2le nle 10^6)


    垃圾分类讨论题,随便测一测就写完了(

    #include<bits/stdc++.h>
    using namespace std;
    int n, d;
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> d;
    	if(d == 9){
    		if(n & 7) putchar((n & 7) | '0');
    		for(int i = n>>3;i;-- i) putchar('8');
    	} else if(!d || n % 9 != d){
    		if(n % 9) putchar(n % 9 + '0');
    		for(int i = n/9;i;-- i) putchar('9');
    	} else if(d == 8){
    		putchar('1'); putchar('7');
    		for(int i = n/9;i;-- i) putchar('9');
    	} else if(n > 9){
    		putchar(d + '1'); putchar('8');
    		for(int i = n/9;i > 1;-- i) putchar('9');
    	} else printf("1%d
    ", n-1);
    }
    

    F Dominating Subarray

    对于两个长为 (k) 的正整数列 (b,c),称 (b) 偏序 (c) 当且仅当 (b_ige c_i)

    给定长为 (n) 的正整数列 (a) 和正整数 (k),求一个偏序所有长为 (k) 的子段的长为 (k) 的子段。

    (kle nle 10^5)(a_ile 10^6)


    (k=n) 时显然有解,否则还是分类讨论:

    • 若是前缀,则 (a_ile a_{min(k,i-1)}pod{ige 2})
    • 若是后缀,则 (a_ile a_{max(n-k,i)+1}pod{i<n})
    • 否则,必须是连续 (k) 个最大值。

    直接判即可,时间复杂度 (O(n))

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 100003;
    template<typename T>
    bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;} 
    int n, k, a[N], mx;
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> k;
    	if(k == n){putchar('1'); return 0;}
    	for(int i = 1;i <= n;++ i){cin >> a[i]; chmax(mx, a[i]);}
    	bool flg = true;
    	for(int i = 2;i <= n && flg;++ i) flg &= a[i] <= a[min(k,i-1)];
    	if(flg){putchar('1'); return 0;}
    	flg = true;
    	for(int i = n-1;i && flg;-- i) flg &= a[i] <= a[max(n-k,i)+1];
    	if(flg){printf("%d", n-k+1); return 0;}
    	for(int i = 2, j = 0;i < n;++ i)
    		if(a[i] == mx){
    			if(++j == k){printf("%d", i-k+1); return 0;}
    		} else j = 0;
    	puts("-1");
    }
    

    D Distance in Crosses

    【题目描述略】

    显然十字也构成四连通网格,所以也是算曼哈顿距离。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    LL xa, ya, xb, yb;
    LL div5(LL x){return x >= 0 ? (x+2) / 5 : (x-2) / 5;}
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> xa >> ya >> xb >> yb;
    	LL x1 = div5(2*xa+ya), y1 = div5(xa-2*ya), x2 = div5(2*xb+yb), y2 = div5(xb-2*yb);
    	printf("%lld
    ", llabs(x1-x2) + llabs(y1-y2));
    }
    

    I Multiplication

    这是一道交互题

    交互库有一个奇数 (xin[1,2^{31}-1]),给定正偶数 (n),你需要给出 (n)(<2^{31}) 的不同自然数 (a_i),交互库会随机抽取其中的 (n/2)(a_i),将 (b_i=a_ixmod 2^{31}) 打乱之后告诉你,求 (x)

    (4le nle 10^5)


    你给出的 (a_i) 直接取随机奇数即可。

    首先看 (b_1),有 (x^{-1}=a_{?}cdot b_1^{-1}),将可能的 (n)(x^{-1}) 算出来,然后用 (forall i,b_icdot x^{-1}=a_{?}) 大力判断。期望复杂度 (O(n))

    不要贪图侥幸直接随机,必须用个 set 去重。

    而且这个模 (2^{31}) 好阴间啊,能不能直接模 (2^{32}) 爽快点(

    #include<bits/stdc++.h>
    #define PB emplace_back
    using namespace std;
    const int N = 100003;
    const unsigned ALL = -1u>>1;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    int n, m, pos[N];
    unsigned b[N], ans;
    set<unsigned> S;
    unsigned Inv(unsigned x){
    	unsigned res = 1;
    	for(int i = 1;i < 31;++ i)
    		if(res*x>>i&1) res |= 1u<<i;
    	return res;
    }
    vector<unsigned> res;
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n; m = n>>1;
    	while(S.size() < n) S.insert((rng()&ALL)|1);
    	for(unsigned u : S) cout << u << ' ';
    	cout << endl;
    	for(int i = 0;i < m;++ i)
    		cin >> b[i];
    	unsigned tmp = Inv(b[0]);
    	for(unsigned u : S) res.PB(u*tmp&ALL);
    	for(int i = 1;i < m && res.size() > 1;++ i){
    		vector<unsigned> nxt;
    		for(unsigned x : res){
    			unsigned tmp = b[i]*x&ALL;
    			if(S.count(tmp)) nxt.PB(x);
    		} res.swap(nxt);
    	}
    	cout << Inv(res[0]) << endl;
    }
    

    A Create the Best Pet

    【题目描述略】

    也就只能大力枚举判断了,因为用 Gene 判比较快所以先用 Gene 判再用 Power 判,跑个几秒就跑出来了。

    #include<bits/stdc++.h>
    using namespace std;
    const unsigned ALL = -1u>>1;
    template<typename T>
    bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    struct u31 {
    	unsigned x;
    	u31(unsigned a = 0): x(a&ALL){}
    	u31 operator + (const u31 &o) const {return x + o.x & ALL;}
    	u31 operator * (const u31 &o) const {return x * o.x & ALL;}
    	u31 Inv() const {
    		unsigned res = 1;
    		for(int i = 1;i < 31;++ i)
    			if(res*x>>i&1) res ^= 1u<<i;
    		return res;
    	}
    };
    u31 calc(const string &s){
    	int len = s.size(); u31 res;
    	for(int i = 0;i < len;++ i)
    		res = res * 31 + s[i];
    	return res;
    }
    int mx, ans[8], info[8];
    unsigned pos;
    int main(){
    	unsigned L, R; string str;
    	ios::sync_with_stdio(false);
    	cin >> L >> R >> str; R += L;
    	unsigned _ = /*Magic Number*/^calc(str).x;
    	for(unsigned i = L;i <= R;++ i){
    		u31 sd(_ ^ i);
    		int scr = 0, tmp[8];
    		for(int i = 0;i < 8;++ i){
    			tmp[i] = 0;
    			for(int j = 0;j < 10000;++ j){
    				sd = sd * 1234567893 + 151515151;
    				tmp[i] += sd.x % 3 - 1;
    			}
    			scr += abs(tmp[i]);
    		}
    		if(chmax(mx, scr)){
    			pos = i;
    			for(int i = 0;i < 8;++ i) ans[i] = tmp[i] + 500;
    			for(int i = 0;i < 8;++ i){
    				sd = sd * 1234567893 + 151515151;
    				info[i] = sd.x % 5;
    			}
    		}
    	}
    	printf("%u %.3f
    ", pos, mx / 8.);
    	for(int i = 0;i < 8;++ i) printf("%d ", ans[i]);
    	putchar('
    ');
    	for(int i = 0;i < 8;++ i) printf("%d ", info[i]);
    }
    

    J Guess Two Strings

    这是个 jb 的交互题

    出题人有两个长为 (n)( exttt{01}) 字符串 (S,T),他按如下方式生成 (q)( exttt{01}) 字符串并告诉你,求 (S,T)

    • 随机选 (S)(T) 之一,翻转随机的 (k) 个 bit。

    (n=q=100)(k=15)(Sle T)


    这种东西显然直接瞎搞搞就行了。

    输入的 (q) 个串形成两个团。随机枚举其中两个串,假装它们属于不同的团,按其他串到它们的汉明距离划分成两个团。求 (S,T) 的时候直接对每一位取众数即可。期望复杂度 (O(nq))

    #include<bits/stdc++.h>
    using namespace std;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 
    int n, k, q;
    string S[100], ans[2];
    bool a[100];
    int dis(const string &a, const string &b){
    	int res = 0;
    	for(int i = 0;i < n;++ i) res += a[i] != b[i];
    	return res;
    }
    bool work(){
    	int p1 = rng() % q, p2 = rng() % q;
    	if(p1 == p2) return true;
    	for(int i = 0;i < q;++ i)
    		a[i] = dis(S[i], S[p1]) > dis(S[i], S[p2]);
    	for(int _ = 0;_ < 2;++ _)
    		for(int i = 0;i < n;++ i){
    			int cnt[2] = {};
    			for(int j = 0;j < q;++ j)
    				if(a[j] == _) ++ cnt[S[j][i] ^ '0'];
    			ans[_][i] = (cnt[0] < cnt[1]) | '0';
    		}
    	for(int i = 0;i < q;++ i)
    		if(dis(S[i], ans[0]) > k && dis(S[i], ans[1]) > k)
    			return true;
    	if(ans[0] > ans[1]) swap(ans[0], ans[1]);
    	return false;
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> k >> q;
    	for(int i = 0;i < q;++ i){
    		cout << '?' << endl;
    		cin >> S[i];
    	}
    	ans[0].resize(n);
    	ans[1].resize(n);
    	while(work());
    	cout << "! " << ans[0] << ' ' << ans[1] << endl;
    }
    

    K Beautiful Tables

    【题目描述略】

    显然题目条件是每行每列形成等差数列,随便手玩一下就知道等价于存在四个数 (a,b,c,d),使得 (a_{i,j}=a+bi+cj+dij),直接解线性方程组即可。

    最后蜜汁 WA 没调出来,赛后仔细看看才发现是分母算出负数了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    int n, m, cnt;
    char str[10];
    LL gcd(LL a, LL b){return b ? gcd(b, a % b) : a;}
    struct Frac {
    	LL a, b;
    	Frac(LL x = 0, LL y = 1){LL g = gcd(x, y); a = x / g; b = y / g; if(b < 0){a = -a; b = -b;}}
    	Frac operator + (const Frac &o) const {
    		LL g = gcd(b, o.b);
    		return Frac(o.b / g * a + b / g * o.a, b / g * o.b);
    	}
    	Frac operator - (const Frac &o) const {
    		LL g = gcd(b, o.b);
    		return Frac(o.b / g * a - b / g * o.a, b / g * o.b);
    	}
    	Frac operator * (const Frac &o) const {
    		LL g1 = gcd(b, o.a), g2 = gcd(a, o.b);
    		return Frac(a / g2 * (o.a / g1), b / g1 * (o.b / g2));
    	}
    	Frac Inv() const {return Frac(b, a);}
    	Frac operator / (const Frac &o) const {return this->operator*(o.Inv());}
    	operator bool() const {return a;}
    	friend ostream& operator << (ostream& out, const Frac &o){
    		out << o.a << '/' << o.b; return out;
    	}
    } mat[4][5], tmp[5];
    void Ins(Frac *a){
    	for(int i = 0;i < 4;++ i) if(a[i]){
    		if(!mat[i][i]){
    			for(int j = i+1;j < 5;++ j) mat[i][j] = a[j] / a[i];
    			mat[i][i] = 1; ++cnt; return;
    		}
    		for(int j = i+1;j < 5;++ j) a[j] = a[j] - a[i] * mat[i][j];
    		a[i] = 0;
    	}
    	if(a[4]){cout << "None" << endl; exit(0);}
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> m;
    	if(n == 1){tmp[1] = 1; tmp[0] = tmp[2] = tmp[3] = tmp[4] = 0; Ins(tmp);}
    	if(m == 1){tmp[2] = 1; tmp[0] = tmp[1] = tmp[3] = tmp[4] = 0; Ins(tmp);}
    	if(n == 1 || m == 1){tmp[3] = 1; tmp[0] = tmp[1] = tmp[2] = tmp[4] = 0; Ins(tmp);}
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j){
    			cin >> str;
    			if(str[0] != '?'){
    				tmp[0] = 1; tmp[1] = i;
    				tmp[2] = j; tmp[3] = i*j;
    				tmp[4] = atoi(str); Ins(tmp);
    			}
    		}
    	if(cnt == 4){
    		for(int i = 3;~i;-- i){
    			tmp[i] = mat[i][4];
    			for(int j = i+1;j < 4;++ j)
    				tmp[i] = tmp[i] - mat[i][j] * tmp[j];
    		}
    		cout << "Unique" << endl;
    		for(int i = 0;i < n;++ i){
    			for(int j = 0;j < m;++ j)
    				cout << tmp[0]+tmp[1]*Frac(i)+tmp[2]*Frac(j)+tmp[3]*Frac(i*j) << ' ';
    			cout << endl;
    		}
    		return 0;
    	}
    	for(int i = 3;~i;-- i){
    		tmp[i] = mat[i][4];
    		for(int j = i+1;j < 4;++ j)
    			tmp[i] = tmp[i] - mat[i][j] * tmp[j];
    	}
    	cout << "Multiple" << endl;
    	for(int i = 0;i < n;++ i){
    		for(int j = 0;j < m;++ j)
    			cout << tmp[0]+tmp[1]*Frac(i)+tmp[2]*Frac(j)+tmp[3]*Frac(i*j) << ' ';
    		cout << endl;
    	}
    	cout << "and" << endl;
    	for(int i = 3;~i;-- i){
    		tmp[i] = mat[i][i] ? mat[i][4] : Frac(1);
    		for(int j = i+1;j < 4;++ j)
    			tmp[i] = tmp[i] - mat[i][j] * tmp[j];
    	}
    	for(int i = 0;i < n;++ i){
    		for(int j = 0;j < m;++ j)
    			cout << tmp[0]+tmp[1]*Frac(i)+tmp[2]*Frac(j)+tmp[3]*Frac(i*j) << ' ';
    		cout << endl;
    	}
    }
    

    H Galactic Governments

    给定 ([0,C]^k)(n) 个子长方体,求水平序最小的不在任何一个长方体内的格子。

    (nle 18)(kle 10)(Cle 1000)


    二分之后转化为算一个子长方体与这 (n) 个子长方体的并的交,直接容斥,时间复杂度 (O(2^nklog C))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int mod = 1073740847;
    int n, k, C, a[18][10], b[18][10], L[10], R[10];
    void qmo(int &x){x += x >> 31 & mod;}
    template<typename T>
    bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    template<typename T>
    bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
    int dfs(int d){
        for(int i = 0;i < k;++ i) if(L[i] >= R[i]) return 0;
        if(d == n){
            int ans = 1;
            for(int i = 0;i < k;++ i) ans = (LL)ans * (R[i]-L[i]) % mod;
            return ans;
        }
        int tl[10], tr[10], ans = dfs(d+1);
        memcpy(tl, L, sizeof L); memcpy(tr, R, sizeof R);
        for(int i = 0;i < k;++ i){
            chmax(L[i], a[d][i]); chmin(R[i], b[d][i]);
        }
        qmo(ans -= dfs(d+1));
        memcpy(L, tl, sizeof L); memcpy(R, tr, sizeof R);
        return ans;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin >> n >> k >> C;
        for(int i = 0;i < k;++ i) R[i] = C;
        for(int i = 0;i < n;++ i){
            for(int j = 0;j < k;++ j) cin >> a[i][j];
            for(int j = 0;j < k;++ j) cin >> b[i][j];
        }
        if(!dfs(0)){puts("NO"); return 0;}
        puts("YES");
        for(int i = 0;i < k;++ i){
            while(L[i] + 1 < R[i]){
                int tmp = R[i]; R[i] = L[i] + R[i] >> 1;
                if(!dfs(0)){L[i] = R[i]; R[i] = tmp;}
            }
            printf("%d ", L[i]);
        }
    }
    

    C Clique Festival

    给定 (n) 个点的无向连通图,其边集是 (k) 个边权相同的团 (C_i),求两两最短路长度之和。

    (nle 10^5)(kle 18)(1le wle 10^7)(sum |C_i|le 3cdot 10^5)


    考虑两个点 (u,v) 之间的最短路,因为团比较少所以转化为团之间的最短路。

    建有向图 (G) 表示若 (C_icap C_j evarnothing) 则连边 (i o j),边权为 (a_j),设 (u,v) 分别属于 (C_i,C_j),则 ( ext{dis}(u,v)=min_{i,j}{ ext{dis}_G(i,j)+a_i})

    ( ext{dis}_G(i,j)) 显然很容易算。考虑按权值从小到大枚举 ((i,j)),数出对应的 (u,v) 数量。设 (D_i) 表示所有处理过的 ((i,j))(j) 的集合。

    枚举 (u)(v) 的取值是 (C_jackslashigcuplimits_{C_asupseteq u,bin D_a}C_b),这个是可以 (O(k2^k)) 预处理 (O(k)) 计算的,具体不太好描述就不写了

    总时间复杂度 (O(k^2sum |C_i|+k2^k+nk^2/w)),好像吊打标算了,改天出到模拟赛里

    #include<bits/stdc++.h>
    #define PB emplace_back
    #define fi first
    #define se second
    #define ALL(x) x.begin(), x.end()
    using namespace std;
    typedef pair<int, int> pii;
    typedef long long LL;
    const int N = 100003, M = 1<<18;
    template<typename T>
    bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
    int n, K, lim, a[18], G[18][18], msk[N], b[M], d[18];
    LL ans;
    bitset<N> C[18];
    vector<pii> vec;
    vector<int> VC[18];
    int main(){
        ios::sync_with_stdio(false);
        cin >> n >> K; lim = 1<<K;
        for(int i = 0, m;i < K;++ i){
            cin >> a[i] >> m; VC[i].resize(m);
            for(int j = 0;j < m;++ j){
                cin >> VC[i][j];
                msk[--VC[i][j]] |= 1<<i;
                C[i].set(VC[i][j]);
            }
        }
        for(int i = 0;i < n;++ i) ++ b[msk[i]];
        for(int S = 1;S < lim;++ S){
            int res = 1e9;
            for(int u = 0;u < K;++ u) if(S>>u&1) chmin(res, a[u]);
            ans -= (LL)res*b[S];
        }
        for(int i = 1;i < lim;i <<= 1)
            for(int j = 0;j < lim;j += i<<1)
                for(int k = 0;k < i;++ k)
                    b[i+j+k] += b[j+k];
        for(int i = 0;i < K;++ i)
            for(int j = 0;j < K;++ j)
                G[i][j] = i == j ? 0 : ((C[i] & C[j]).any() ? a[j] : 1e9);
        for(int k = 0;k < K;++ k)
            for(int i = 0;i < K;++ i)
                for(int j = 0;j < K;++ j)
                    chmin(G[i][j], G[i][k] + G[k][j]);
        for(int i = 0;i < K;++ i)
            for(int j = 0;j < K;++ j){
                G[i][j] += a[i]; vec.PB(i, j);
            }
        sort(ALL(vec), [&](const pii &a, const pii &b){return G[a.fi][a.se] < G[b.fi][b.se];});
        for(pii _ : vec){
            int ca = _.fi, cb = _.se;
            LL res = 0;
            for(int u : VC[ca]){
                int tmp = 0;
                for(int i = 0;i < K;++ i)
                    if(msk[u]>>i&1) tmp |= d[i];
                tmp ^= lim-1; res += b[tmp] - b[tmp&~(1<<cb)];
            } d[ca] |= 1<<cb; ans += res*G[ca][cb];
        }
        printf("%lld
    ", ans>>1);
    }
    

    B Graph and Machine

    给定 (k) 个点 (m) 条边的无向简单连通图 ((V,E)),每个点 (u) 有点权 (c_uin{0,1})

    给定 (N) 个点的 DAG,点 (s) 没有入边,称为源点,点 (t_0,t_1) 没有出边,称为汇点,汇点之外的点 (u) 有标记 (l_uin{1,2,cdots,m}),且有两条出边分别连向 (o_{u,0})(o_{u,1})

    判断是否 (forall (x_1,x_2,cdots,x_m)in{0,1}^m),在 DAG 上从 (s) 出发,每次从 (u) 走到 (o_{u,c_{l_u}}),最终走到 (t_1) 当且仅当 (forall uin V,igopluslimits_{(u,v)in E} x_u=c_v)

    (N,mle 3cdot 10^5)(Nge 3)对于所有从源点到汇点的路径,经过的点的标记不同

    【未完待续】

  • 相关阅读:
    IntelliJ IDEA 安装和破解教程
    IntelliJ IDEA 快捷键
    分布式事务框架-seata初识
    Spring超详细总结
    spring注解之@Import注解的三种使用方式
    双亲委托模型
    日志管理-log4j与slf4j的使用
    最详细的自定义Spring Boot Starter开发教程
    深入JVM(二)JVM概述
    一篇长文说 git 基础
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/15229313.html
Copyright © 2020-2023  润新知