2022河南萌新联赛第(三)场:河南大学

A-玉米大炮

二分一个时间,然后计算每门大炮可以射击的次数

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n,m;
    cin>>n>>m;
    vector<int>a(n),b(n);
    for(int i=0;i<n;++i)cin>>a[i]>>b[i];
    int l=0,r=1e18,x;
    auto check=[&](int s){
        __int128 ans=0;
        for(int i=0;i<n;++i){
            __int128 c=s/b[i]+1;
            ans+=a[i]*c;
        }
        return ans>=(__int128)m;
    };
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid))r=mid-1,x=mid;
        else l=mid+1;
    }
    cout<<x;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

B-逆序对计数

因为长度比较小,所以直接预处理每个区间的逆序对个数,翻转区间只会导致区间内的逆序对数量发生改变。

预处理就对前缀反复的做逆序对即可。

#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long

const int p = 1e9 + 7;
const int pp = 998244353;

int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};

ll ksm(ll a, ll b, ll p) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = (ans * a) % p;
        b >>= 1;
        a = (a * a) % p;
    }
    return ans % p;
}

std::mt19937 rng;  // 随机数生成器  
int rand(int l, int r) {
    std::uniform_int_distribution<int> distribution(l, r);
    return distribution(rng);
}

class BIT {
public:
    BIT(int size) : size_(size), tree_(size + 1, 0) {}

    void update(int index, int delta) {
        for (int i = index + 1; i <= size_; i += (i & -i)) {
            tree_[i] += delta;
        }
    }

    int query(int index) {
        int sum = 0;
        for (int i = index + 1; i > 0; i -= (i & -i)) {
            sum += tree_[i];
        }
        return sum;
    }

    int queryRange(int left, int right) {
        return query(right) - query(left - 1);
    }

private:
    int size_;
    vector<int> tree_;
};

const int N = 6005;
int n;
int a[N], f[N][N];

void solve() {
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for(int i = n; i; i--) {
		BIT b(n + 1);
		for(int j = i + 1; j <= n; j++) {
			b.update(a[j], 1);
			f[i][j] = b.query(a[i]);
            f[i][j] += f[i + 1][j];
		}
	}
//     for(int i = 1; i <= n; i++) {
//         for(int j = 1; j <= n; j++) {
//             cout << f[i][j] << " \n"[j == n];
//         }
//     }
	int ans = f[1][n];
	int q;
	cin >> q;
	while(q -- ) {
		int l, r;
		cin >> l >> r;
		int len = (r - l + 1);
		cout << ((ans - f[l][r]) + (len * (len - 1) >> 1) - f[l][r]) << endl;
	}
}


/*



*/

signed main () {
//     init(minp, primes, m); // primes
    // init();
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int _ = 1;
//   cin >> _;
    while(_ -- ) {
        solve();
    }
    return 0;
}

C-区间操作

其实\(f(x)\)就是求质因数分解后有多少个质因数,而opt1是求\(f(\sum b_i)\),所以直接存储每个数的质因数个数即可,题目转换为了区间修改,区间求和。套一个线段树的模板即可。

#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long

const int p = 1e9 + 7;
const int pp = 998244353;

int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};

ll ksm(ll a, ll b, ll p) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = (ans * a) % p;
        b >>= 1;
        a = (a * a) % p;
    }
    return ans % p;
}

std::mt19937 rng;  // 随机数生成器  
int rand(int l, int r) {
    std::uniform_int_distribution<int> distribution(l, r);
    return distribution(rng);
}

class SegmentTree {  
public:  
    SegmentTree(vector<int>& nums) {  
        n = nums.size() - 1;  
        tree.resize(4 * n + 1);  
        lazy.resize(4 * n + 1);  
        build(nums, 1, 1, n);  
    }  
  
    void build(vector<int>& nums, int i, int start, int end) {  
        if (start == end) {  
            tree[i] = nums[start];  
            return;  
        }  
        int mid = (start + end) / 2;  
        build(nums, 2 * i, start, mid);  
        build(nums, 2 * i + 1, mid + 1, end);  
        tree[i] = tree[2 * i] + tree[2 * i + 1];  
    }  
  
    void push_up(int i, int start, int end) {  
        tree[i] = tree[2 * i] + tree[2 * i + 1];  
    }  
  
    void push_down(int i, int start, int end) {  
        if (lazy[i] != 0) {  
            int mid = (start + end) / 2;  
            lazy[2 * i] += lazy[i];  
            lazy[2 * i + 1] += lazy[i];  
            tree[2 * i] += lazy[i] * (mid - start + 1);  
            tree[2 * i + 1] += lazy[i] * (end - mid);  
            lazy[i] = 0;  
        }  
    }  
  
    void update(int i, int start, int end, int s, int e, int val) {  
        if (s <= start && end <= e) {  
            tree[i] += val * (end - start + 1);  
            lazy[i] += val;  
            return;  
        }  
        push_down(i, start, end);  
        int mid = (start + end) / 2;  
        if (s <= mid) update(2 * i, start, mid, s, e, val);  
        if (e > mid) update(2 * i + 1, mid + 1, end, s, e, val);  
        push_up(i, start, end);  
    }  
  
    int query(int i, int start, int end, int s, int e) {  
        if (s <= start && end <= e) return tree[i];  
        push_down(i, start, end);  
        int mid = (start + end) / 2;  
        int count = 0;  
        if (s <= mid) count += query(2 * i, start, mid, s, e);  
        if (e > mid) count += query(2 * i + 1, mid + 1, end, s, e);  
        return count;  
    }  
  
    void updateRange(int s, int e, int val) {  
        update(1, 1, n, s, e, val);  
    }  
  
    int queryRange(int s, int e) {  
        return query(1, 1, n, s, e);  
    }  
  
private:  
    int n;  
    vector<int> tree;  
    vector<int> lazy;  
};

const int m = 4e6;
vector<int> minp(m + 10), primes;
void init(vector<int> & minp, vector<int> & primes, int ma) {
    for(int i = 2; i <= ma; i++) {
        if(!minp[i]) {
            minp[i] = i;
            primes.emplace_back(i);
        }
        for(auto & p : primes) {
            if(i * p > ma) break;
            minp[i * p] = p;
            if(p == minp[i]) break;
        }
    }
}

int n, q;
vector<int> a;

int f(int x) {
	int ans = 0;
	while(x > 1) {
		x /= minp[x];
		ans ++ ;
	}
	return ans;
}

void solve() {
	cin >> n;
	a = vector<int>(n + 1);
	for(int i = 1, x; i <= n; i++) {
		cin >> x;
		while(x > 1) {
			a[i] ++ ;
			x /= minp[x];
		}
	}
	SegmentTree tr(a);
	cin >> q;
	while(q -- ) {
		int op, l, r;
		cin >> op >> l >> r;
		if(op == 1) {
			cout << tr.queryRange(l, r) << endl;
		}
		else {
			int w;
			cin >> w;
			tr.updateRange(l, r, f(w));
		}
	}
}


/*



*/

signed main () {
     init(minp, primes, m); // primes
    // init();
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int _ = 1;
//   cin >> _;
    while(_ -- ) {
        solve();
    }
    return 0;
}

D-小蓝的新技能

首先一个引理是

\[\gcd(x^3,y^3) = gcd(x,y)^3 \]

所以根据题目,我们可以得出

\[(ab)^3 = gcd(a,b)^3(n - \gcd(a,b)^3) \]

并且当\(b\)取最小值\(1\)时,可以得到\(a^3=n\),所以\(a^3 \le 10^5\)

所以可以暴力的枚举\(a\),然后枚举\(a\)的因子做\(\gcd(a,b)\),然后带入上式反解出\(b\),然后只需要判断\(b\)是否合法即可。

#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long

const int p = 1e9 + 7;
const int pp = 998244353;

int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};

ll ksm(ll a, ll b, ll p) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = (ans * a) % p;
        b >>= 1;
        a = (a * a) % p;
    }
    return ans % p;
}

std::mt19937 rng;  // 随机数生成器  
int rand(int l, int r) {
    std::uniform_int_distribution<int> distribution(l, r);
    return distribution(rng);
}

vector<int> d[201010];
int n;
void init() {
	for(int i = 1; i <= 2e5; i++) {
		for(int j = i; j <= 2e5; j += i) {
			d[j].emplace_back(i);
		}
	}
}

int sqrt(int x) {
	int l = 0, r = 1e5;
	while(l < r) {
		int mid = (l + r + 1) >> 1;
		if(mid * mid * mid <= x) l = mid;
		else r = mid - 1;
	}
	if(l * l * l != x) return -1;
	return l;
}

void solve() {
	cin >> n;
	int ans = 0;
	for(int a = 1; a <= 1e5; a++) {
		for(auto & g : d[a]) {
			int m = n - g * g * g;
			int sq = sqrt(m);
			if(sq == -1) continue;
//             cout << "g : " << g << endl;
//             cout << "l3 : " << m << ", sq : " << sq << endl;
			int ab = sq * g;
//             cout << ab << endl;
			if(ab > 0 && ab % a == 0 && g * g * g + sq * sq * sq == n && __gcd(a, ab / a) == g) {
//                 cout << "a : " << a << ", b : " << ab / a << endl;
				ans ++ ;
                break;
			}
		}
	}
	cout << ans << endl;
}


/*



*/

signed main () {
//     init(minp, primes, m); // primes
     init();
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while(_ -- ) {
        solve();
    }
    return 0;
}

E-演算任务

其实就是简单的背包问题,\(f[i][j][0/1]\)\(i\)个数组合出\(j\)有没有使用除2的最小花费。

难点其实是第二位可能是负数,所以要偏移一下。

#include<bits/stdc++.h>

using namespace std;

using vi = vector<int>;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

//#define int i64

using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = LLONG_MAX;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, x;
    cin >> n >> x;
    int N = abs(x) + n * 100;
    vector f(2, vector(2, vi(N * 2 + 1, inf)));
    f[0][0][0 + N] = 0;
    int i = 1;
    for (int v; n; n--, i ^= 1) {
        cin >> v;
        for (int j = -N, t; j <= N; j++) {
            t = j + v;
            if (-N <= t and t <= N) {
                f[i][0][t + N] = min(f[i ^ 1][0][t + N], f[i ^ 1][0][j + N] + 1);
                f[i][1][t + N] = min(f[i ^ 1][1][t + N], f[i ^ 1][1][j + N] + 1);
            }
            t = (j + v) / 2;

            if (-N <= t and t <= N) {
                f[i][1][t + N] = min({f[i][1][t + N], f[i ^ 1][1][t + N], f[i ^ 1][0][j + N] + 1});
            }
        }
    }
    int res = min(f[i ^ 1][0][x + N], f[i ^ 1][1][x + N]);
    if (res == inf) res = -1;

    cout << res << "\n";
    return 0;
}

F-爱学习的小蓝

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
using i128 = __int128;
const int inf = INT_MAX, INF = LLONG_MAX;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

vector t = {2, 8, 8, 18, 18, 32, 32};


void solve() {
    int n, res = 0;
    cin >> n;
    for (const auto i: t) {
        res++;
        n -= i;
        if (n <= 0)break;
    }
    cout << res << "\n";
    return;
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

H-树上问题

换根dp

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef long long ll;
typedef pair<ll, ll> P;
#define int long long

int n;
vector<vector<int>> g;
vector<int> a, val, son, mx, val2;

int dfs1(int u, int fa) {
    for(auto & ne : g[u]) {
        if(ne == fa) continue;
        int d = dfs1(ne, u) + a[ne];
        if(d > val[u]) {
            val2[u] = val[u];
            val[u] = d;
            son[u] = ne;
        }
        else if(d > val2[u]) {
            val2[u] = d;
        }
    }
    return val[u];
}

void dfs2(int u, int fa, int now) {
    mx[u] = max(val[u], now) + a[u];
    for(auto & ne : g[u]) {
        if(ne == fa) continue;
        if(ne == son[u]) { // 重儿子
            dfs2(ne, u, max(now, val2[u]) + a[u]);
        }
        else {
            dfs2(ne, u, max(now, val[u]) + a[u]);
        }
    }
}

signed main () {
    cin >> n;
    mx = son = val = val2 = a = vector<int>(n + 1);
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    g = vector<vector<int>>(n + 1);
    for(int i = 0, u, v; i < n - 1; i++) {
        cin >> u >> v;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    dfs1(1, 0);
    dfs2(1, 0, 0);
    int ans = 0;
    for(int i = 1; i <= n; i++) {
        int d1 = 0, d2 = 0;
        for(auto & ne : g[i]) {
            if(mx[ne] > d1) {
                d2 = d1;
                d1 = mx[ne];
            }
            else if(mx[ne] > d2) {
                d2 = mx[ne];
            }
        }
        ans = max(ans, d1 + d2 + mx[i]);
    }
    cout << ans << endl;
    return 0;
}

I-旅行

把点分成\((x,0/1)\)表示在\(x\)点有没有做核酸,然后不能连续经过两个0,因此建图

\[((u,0),(v,1),w+x)\\ ((u,1),(v,0),w)\\ ((u,1),(v,1),w+2) \]

以及他们的反向边,然后跑最短路就行

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
using i128 = __int128;
const int inf = INT_MAX, INF = LLONG_MAX;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m, x;
    cin >> n >> m >> x;
    vi dis(n * 2 + 1, INF);
    dis[1] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> q;
    q.emplace(0, 1);
    vector<vector<pii>> e(n * 2 + 1);
    for (int u, v, w; m; m--) {
        cin >> u >> v >> w;
        e[u].emplace_back(v + n, w + x);
        e[u + n].emplace_back(v, w);
        e[u + n].emplace_back(v + n, w + x);
        e[v].emplace_back(u + n, w + x);
        e[v + n].emplace_back(u, w);
        e[v + n].emplace_back(v + n, w + x);
    }
    vi vis(n * 2 + 1);
    while (not q.empty()) {
        auto [d, u] = q.top();
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (auto [v, w]: e[u]) {
            if (vis[v] or d + w >= dis[v]) continue;
            dis[v] = d + w;
            q.emplace(dis[v], v);
        }
    }
    cout << min(dis[n], dis[n + n]) << "\n";
    return 0;
}

J-神奇数字

任意两个数差值的gcd就是答案

#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long

const int p = 1e9 + 7;
const int pp = 998244353;

int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};

ll ksm(ll a, ll b, ll p) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = (ans * a) % p;
        b >>= 1;
        a = (a * a) % p;
    }
    return ans % p;
}

std::mt19937 rng;  // 随机数生成器  
int rand(int l, int r) {
    std::uniform_int_distribution<int> distribution(l, r);
    return distribution(rng);
}

vector<int> d[201010];
void init () {
    for(int i = 1; i <= 2e5; i++) {
        for(int j = i; j <= 2e5; j += i) {
            d[j].emplace_back(i);
        }
    }
}

void solve() {
	int a[3] = {};
	for(int i = 0; i < 3; i++) {
		cin >> a[i];
	}
	sort(a, a + 3);
	int g = 0;
	for(int i = 0; i < 3; i++) {
		for(int j = i + 1; j < 3; j++) {
			g = __gcd(g, a[j] - a[i]);
		}
	}
//     cout << g << endl;
	if(g == 0) cout << -1 << endl;
	else {
        for(auto & x : d[g]) {
            cout << x << " ";
        }
        cout << endl;
	}
}


/*



*/

signed main () {
//     init(minp, primes, m); // primes
    init();
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int _ = 1;
   cin >> _;
    while(_ -- ) {
        solve();
    }
    return 0;
}

L-合成游戏

找规律

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

int fac[N];
int f[N];
int ksm(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=res*a%Mod;
        b>>=1;
        a=a*a%Mod;
    }
    return res;
}
void init(){
    fac[0]=f[0]=1;
    int c=ksm(2,Mod-2);
    for(int i=1;i<=1e5;++i){
        fac[i]=fac[i-1]*i%Mod;
        f[i]=f[i-1]*c%Mod;
    }
}
void solve() {
    int n;
    cin>>n;
    int ans=fac[n];
    while(n>1){
        n/=2;
        ans=ans*f[n]%Mod;
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--){
        solve();
    }
    return 0;
}
posted @ 2024-02-04 19:15  PHarr  阅读(4)  评论(0编辑  收藏  举报