CCPC 2022 网络赛 补题(不是题解)

Multiple set

注意到
l = (L + x - 1) / x;
r = R / x;
K = 2 ^ (r - l - 1) * (r + l) * (r - l + 1) * x;

枚举所有K的因数作为x check 即可,稍微优化一下枚举因数就行

点击查看代码
#include "bits/stdc++.h"
using namespace std;

typedef long long ll;

const int MAXN = 1e7;

ll prime[2000000], vis[MAXN + 10]; 
ll L,R,K;

void init() {
    for (int i=2;i<=MAXN;i++) {
        if (!vis[i]) prime[++prime[0]] = i;
        for (int j = 1;j<=prime[0] && prime[j] * i <= MAXN; j++) {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}

bool check(ll x) {
    ll l = (L + x - 1) / x;
    ll r = R / x;

    if (r - l >60) return false;
    // cout<<x<<' '<<l<<' '<<r<<'\n';

    if (l==r) {
        //cout<<(((r+l) * (r-l+1) * x) >> 1)<<' '<<K<<endl;
        return ((r+l) * (r-l+1) * x) >> 1 == K;
    }
    return (((r+l) * (r-l+1) * x) << (r - l - 1)) == K;
}
 
void solve() {
    

    cin>>L>>R>>K;

    vector<ll> knum;
    knum.push_back(1);

    ll k = K;
    for (int i=1;i<=prime[0] && prime[i] <= K;i++) {
        ll p = 1;
        queue<ll> add;
        while (k%prime[i] == 0) {
            k /= prime[i];
            p *= prime[i];
            for (int j=0;j<knum.size();j++) {
                add.push(knum[j] * p);
            }
        }
        while (!add.empty()) {
            knum.push_back(add.front());
            add.pop();
        }
    }
    
    int num = 0;
    vector<ll> ans;

    for (int i=0;i<knum.size();i++) {
        if (check(knum[i])) {
            ans.push_back(knum[i]);
        }
        if (ans.size() > 100000) break;
    }

    if (ans.size() > 100000) {
        cout<<"Too Many!\n";
    } else if (ans.size() == 0) {
        cout<<"No Solution\n";
    } else {
        cout<<ans.size()<<'\n';
        for (int i=0;i<ans.size();i++) cout<<ans[i]<<' ';
        cout<<'\n';
    }
/*
    x;
    l = (L + x - 1) / x;
    r = R / x;

    K = 2 ^ (r - l - 1) * (r + l) * (r - l + 1)  * x;

*/
}

int main() {

    // ios::sync_with_stdio(false);
    // cin.tie(0);

    init();

    int T;
    cin>>T;
    while (T--) solve();

    return 0;
}

Transport Plan

很天才的想法,把直线拉到二维,在二维上维护 ans[i][j] //代表建立 (i,j) 传送门能使最终cost减少 ans[i][j]
然后考虑每一个运输计划 a,b,v 对它的贡献

ans[i][j] += v|a - b| - max(0, |a - b| - dis((a,b), (i,j))) //dis 是哈密顿距离

如图: 一个 v = 4 的贡献

点击查看代码
      1
    1 2 1
  1 2 3 2 1
1 2 3 4 3 2 1
  1 2 3 2 1
    1 2 1
      1

一次横向差分

      1 -1
    1 1 -1 -1
  1 1 1 -1 -1 -1 
1 1 1 1 -1 -1 -1 -1
  1 1 1 -1 -1 -1
    1 1 -1 -1
      1 -1

二次横向差分

      1 -2 1
    1 0 -2 0 1
  1 0 0 -2 0 0 1
1 0 0 0 -2 0 0 0 1
  1 0 0 -2 0 0 1
    1 0 -2 0 1
      1 -2 1

二次横向 + 一次斜向差分
       
      。。。

后面是两次斜向加一次纵向差分
最后能 O(1) 修改
只要能最后前缀和回去就行。。。

还有边界问题
。。。

不想补了hhh

posted @ 2025-03-27 16:25  Woxuany1  阅读(30)  评论(0)    收藏  举报