AtCoder Regular Contest 104 D(卡常)

考虑对每个x计算答案.

将除x以外的数都减去x,答案就是这些数的多重集(可以为空)和为0的方案数乘上(K+1), 最后加一个 k个 x

然而, t了6个点(别走Ψ( ̄∀ ̄)Ψ)

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 1e2 + 5, M = 1e6 + 5;

int n, m, _, k;
ll f1[M], f2[M];

int main() {
    IOS; cin >> n >> k >> m;
    VI ans; f1[0] = f2[0] = 1;
    rep(i, 1, (n + 1) >> 1) {
        int l = (i - 1) * i / 2 * k, r = (n - i + 1) * (n - i) / 2 * k;
        rep(j, 1, l) f1[j] = 0;
        rep(j, 1, r) f2[j] = 0;
        rep(j, 1, i - 1) {
            int r = (j - 1) * j / 2 * k, d = j * k;
            rep(s, j, r) f1[s] = (f1[s] + f1[s - j]) % m;
            per(s, r, d + j) f1[s] = (f1[s] + m - f1[s - d - j]) % m;
        }
        rep(j, 1, n - i) {
            int r = (j - 1) * j / 2 * k, d = j * k;
            rep(s, j, r) f2[s] = (f2[s] + f2[s - j]) % m;
            per(s, r, d + j) f2[s] = (f2[s] + m - f2[s - d - j]) % m;
        }
        ll res = k;
        per(s, min(l, r), 1) res = (res + f1[s] * f2[s] % m * (k + 1) % m) % m;
        ans.pb(res);
    }
    for (auto i : ans) cout << i << '
';
    per(i, ans.size() - 1 - (n & 1), 0) cout << ans[i] << '
';
    return 0;
}

然而还可以优化, 思路是一样的, 直接把左右区间写成一个区间, 偏移量嘛

假定把 x 左边全部选上,也就是现在是最小值, 左区间全部-x(都是负数), 对于1~N(除了x), 选择 1~x-1, 相当于把最开始选择左区间的数扔掉了, ++a, 选择右区间, 也是 ++a是不是少了一个常数啊?

//对于 1e8小个常数是优化是相当高的

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 1e2 + 5, M = 1e6;

int n, m, _, k;
int a[M << 1], *f;

void add(int& x, int y){
    x += y;
    if(x >= m) x -= m;
}

void sub(int& x, int y){
    x -= y;
    if(x < 0) x += m;
}

int main() {
    IOS; cin >> n >> k >> m;
    VI ans; f = a + M;
    rep(i, 1, (n + 1) >> 1) {
        int l = -(i - 1) * i / 2 * k, r = (n - i + 1) * (n - i) / 2 * k;
        rep(j, l, r) f[j] = 0; f[l] = 1; //左区间全选
        
        VI res;
        rep(j, 1, n) if (i != j) res.pb(abs(j - i)); //都是++a
        sort(all(res)); r = l;
        
        for (int x : res) {
            int d = x * k; r += d;
            rep(j, l + x, r) add(f[j], f[j - x]);
            per(j, r, l + x + d) sub(f[j], f[j - d - x]);
        }
        ans.pb(((ll)f[0] * (k + 1) - 1 + m) % m);
    }
    rep(i, (n + 1 >> 1) + 1, n) ans.pb(ans[n - i]);
    for (int i : ans) cout << i << '
';
    return 0;
}

原文地址:https://www.cnblogs.com/2aptx4869/p/13767505.html