2020 CCPC Wannafly Winter Camp Day6

N
贪心,最后一堆一定是各个元素的积的和

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000 + 5;
typedef long long ll;
int a[maxn];

int main()
{
	ios::sync_with_stdio(false); cin.tie(0);
	int n; cin >> n;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	ll ans = 0;
	for (int i = 1; i <= n; ++i) {
		for (int j = i + 1; j <= n; ++j) {
			ans += 1ll * a[i] * a[j];
		}
	}
	printf("%lld\n", ans);
}

K
构造:展开式系数成中间大后向两边递减的对称分布

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn];
int main()
{
	ios::sync_with_stdio(false); cin.tie(0);

	int n; cin >> n;
	for (int i = 0; i < (n + 1) / 2; ++i) {
		a[i] = 2 * i + 1;
	}
	for (int i = 1, j = 0; j < n / 2; ++j, ++i) {
		a[n - 1 - j] = 2 * i;
	}
	for (int i = 0; i < n; ++i)
		cout << a[i] << ' ';

}

C
暴力模拟

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
char in[maxn];
int n, a, b, c, d, mx_ans, mn_ans;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T; cin >> T;
	while (T--) {
		cin >> n >> a >> b >> c >> d;
		mx_ans = mn_ans = 0;
		cin >> in;
		int aa = a, bb = b, cc = c, dd = d;
		for (int i = 0; in[i]; ++i) {
			if (in[i] == '1') {
				if (cc != 0) {
					cc--; mx_ans++;
				}
				else if (dd != 0) {
					dd--; cc++;
				}
				else if (aa != 0) {
					aa--; mx_ans++;
				}
				else if (bb != 0) {
					bb--; aa++;
				}
			}
			else {
				if (dd != 0) {
					dd--; cc++;
				}
				else if (cc == 0 && bb != 0) {
					bb--; aa++;
				}
			}
		}
		aa = a, bb = b, cc = c, dd = d;
		for (int i = 0; in[i]; ++i) {
			if (in[i] == '1') {
				if (dd != 0) {
					dd--; cc++;
				}
				else if (cc != 0) {
					cc--; mn_ans++;
				}
				else if (bb != 0) {
					bb--; aa++;
				}
				else if (aa != 0) {
					aa--; mn_ans++;
				}
			}
			else {
				if (cc != 0) {

				}
				else if (dd != 0) {
					dd--; cc++;
				}
				else if (aa != 0) {

				}
				else if (bb != 0) {
					bb--; aa++;
				}
			}
		}
		cout << mx_ans << ' ' << mn_ans << '\n';
	}
}

L
bfs

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 5;
int dir[8][2] = {1, 2, 2, 1, 2, -1, 1, -2, -1, -2, -2, -1, -2, 1, -1, 2};
int check_dir[8][2] = {0, 1, 1, 0, 1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0, 1};

char mp[maxn][maxn];
queue<pair<int, int>> q;
int ans[maxn][maxn];
int main()
{

	int n, m; scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%s", mp[i] + 1);
		for (int j = 1; j <= m; ++j) {
			ans[i][j] = -1;
			if (mp[i][j] == 'M') {
				ans[i][j] = 0;
				q.push(make_pair(i, j));
			}
		}
	}
	while (!q.empty()) {
		pair<int, int> p = q.front(); q.pop();
		for (int i = 0; i < 8; ++i) {
			int x = p.first + dir[i][0];
			int y = p.second + dir[i][1];
			if (x < 0 || x > n || y < 0 || y > m) continue;
			if (mp[x][y] != '.') continue;
			if (mp[p.first + check_dir[i][0]][p.second + check_dir[i][1]] == 'X') continue;
			if (ans[x][y] == -1 || ans[x][y] > ans[p.first][p.second] + 1) {
				ans[x][y] = ans[p.first][p.second] + 1;
				q.push(make_pair(x, y));
			}
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			if (j == m)
				printf("%d\n", ans[i][j]);
			else
				printf("%d ", ans[i][j]);
		}
	}
}

M
处理出数据需要内容

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5000 + 5;
vector<int> a[105][12];
int ac_cnt[12], peo_vis[12][105];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n, m, W; cin >> n >> m >> W;
	for (int i = 0; i < W; ++i) {
		int x, y, c; cin >> x >> y >> c;
		a[x][y].push_back(c);
		if (c == 1 && peo_vis[y][x] == 0) {
			peo_vis[y][x] = 1;
			ac_cnt[y]++;
		}
	}
	for (int i = 1; i <= n; ++i) {
		bool no_submit_flg = true;
		int this_ac_cnt = 0;
		ll ans = 0;
		for (int j = 1; j <= 10; ++j) {
			if (a[i][j].size())
				no_submit_flg = false;
			bool is_ac = false;
			int longest_noac = 0, tmp = 0;
			for (int k = 0; k < a[i][j].size(); ++k) {
				if (a[i][j][k] == 0)
					tmp++;
				else {
					is_ac = true;
					longest_noac = max(longest_noac, tmp);
					tmp = 0;
				}
			}
			longest_noac = max(longest_noac, tmp);

			this_ac_cnt += is_ac;
			if (!is_ac && ac_cnt[j])
				ans += 20;
			if (!is_ac && ac_cnt[j] >= n / 2)
				ans += 10;
			ans += 1ll * longest_noac * longest_noac;
			if (!is_ac)
				ans += 1ll * longest_noac * longest_noac;
		}

		if (no_submit_flg)
			cout << 998244353 << '\n';
		else if (this_ac_cnt == m)
			cout << 0 << '\n';
		else if (this_ac_cnt == 0)
			cout << 1000000 << '\n';
		else
			cout << ans << '\n';
	}
}

A
NTT
先将序列遍历转换为范围遍历,令 f ( i ) = ∑ k = 1 n [ a k = = i ] f(i)=\sum_{k=1}^n[a_k==i] f(i)=k=1n[ak==i],原式为 ∑ i = 1 n ∑ j = 1 n f ( i ) f ( j ) 2 i j = 2 ∑ i = 1 n ∑ j = 1 i f ( i ) f ( j ) 2 i j − ∑ i = 1 n f ( i ) 2 2 i 2 \sum_{i=1}^n\sum_{j=1}^nf(i)f(j)2^{ij}=2\sum_{i=1}^n\sum_{j=1}^if(i)f(j)2^{ij}-\sum_{i=1}^nf(i)^22^{i^2} i=1nj=1nf(i)f(j)2ij=2i=1nj=1if(i)f(j)2iji=1nf(i)22i2
根据 2 i j = i 2 + j 2 − ( i − j ) 2 2ij=i^2+j^2-(i-j)^2 2ij=i2+j2(ij)2,则 2 ∑ i = 1 n ∑ j = 1 i f ( i ) f ( j ) 2 i j − ∑ i = 1 n f ( i ) 2 2 i 2 = 2 ∑ i = 1 n ∑ j = 1 i f ( i ) f ( j ) 2 i 2 + j 2 − ( i − j ) 2 − ∑ i = 1 n f ( i ) 2 2 i 2 = 2 ∑ i = 1 n f ( i ) 2 i 2 ∑ j = 1 i f ( j ) 2 j 2 2 − ( i − j ) 2 − ∑ i = 1 n 2 i 2 f ( i ) 2 2\sum_{i=1}^n\sum_{j=1}^if(i)f(j)2^{ij}-\sum_{i=1}^nf(i)^22^{i^2}=2\sum_{i=1}^n\sum_{j=1}^if(i)f(j)\sqrt{2}^{i^2+j^2-(i-j)^2}-\sum_{i=1}^nf(i)^22^{i^2}=2\sum_{i=1}^nf(i)\sqrt{2}^{i^2}\sum_{j=1}^if(j)\sqrt{2}^{j^2}\sqrt{2}^{-(i-j)^2}-\sum_{i=1}^n2^{i^2}f(i)^2 2i=1nj=1if(i)f(j)2iji=1nf(i)22i2=2i=1nj=1if(i)f(j)2 i2+j2(ij)2i=1nf(i)22i2=2i=1nf(i)2 i2j=1if(j)2 j22 (ij)2i=1n2i2f(i)2
∑ i = 1 n f ( i ) 2 i 2 和 ∑ i = 1 n 2 i 2 f ( i ) 2 \sum_{i=1}^nf(i)\sqrt{2}^{i^2}和\sum_{i=1}^n2^{i^2}f(i)^2 i=1nf(i)2 i2i=1n2i2f(i)2可以 O ( n ) O(n) O(n)处理, ∑ j = 1 i f ( j ) 2 j 2 2 − ( i − j ) 2 \sum_{j=1}^if(j)\sqrt{2}^{j^2}\sqrt{2}^{-(i-j)^2} j=1if(j)2 j22 (ij)2是多项式 A i = f ( i ) 2 i 2 和 B i = 2 − i 2 Ai=f(i)\sqrt{2}^{i^2}和Bi=\sqrt{2}^{-i^2} Ai=f(i)2 i2Bi=2 i2的卷积, ∑ j = 0 i a j b i − j = ∑ j = 0 i f ( j ) 2 j 2 2 − ( i − j ) 2 \sum_{j=0}^ia^jb^{i-j}=\sum_{j=0}^{i}{f(j)\sqrt{2}^{j^2}\sqrt{2}^{-(i-j)^2}} j=0iajbij=j=0if(j)2 j22 (ij)2
2 \sqrt{2} 2 使用二次剩余提前求出来

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int P = 998244353;
const int sqr = 116195171;
inline int qpow(int d, ll z)
{
  int ans=1;
  for(; z; z >>= 1, d = 1ll * d * d % P)
    if(z & 1) ans = 1ll * ans * d % P;
  return ans;
}
int r[maxn << 2];
void ntt(int *x, int lim, int opt) {
    register int i, j, k, m, gn, g, tmp;
    for(i = 0; i < lim; i++)
        if(r[i] < i) swap(x[i], x[r[i]]);
    for(m = 2; m <= lim; m <<= 1) {
        k = m >> 1;
        gn = qpow(3, (P - 1) / m);
        for(i = 0; i < lim; i += m) {
            g = 1;
            for(j = 0; j < k; j++, g = 1ll * g * gn % P) {
                tmp = 1ll * x[i + j + k] * g % P;
                x[i + j + k] = (x[i + j] - tmp + P) % P;
                x[i + j] = (x[i + j] + tmp) % P;
            }
        }
    }
    if(opt == -1) {
        reverse(x + 1, x + lim);
        register int inv = qpow(lim, P - 2);
        for(i = 0; i < lim; i++) 
            x[i] = 1ll * x[i] * inv % P;
    }
}
int A[maxn << 2], B[maxn << 2], C[maxn << 2];
int f[1 << 17];
int main()
{
	int n; scanf("%d", &n);
	for (int i = 0; i < n; ++i) {
		int x; scanf("%d", &x);
		f[x]++;
	}
	int lim = 1 << 18;
	for (int i = 0; i <= 1e5; ++i) {
        A[i] = 1ll * f[i] * qpow(sqr, 1ll * i * i) % P;
        B[i] = qpow(sqr, (-1ll * i * i % (P - 1) + P - 1));
	}
    for(int i = 0; i < lim; i++) r[i] = (i & 1) * (lim >> 1) + (r[i >> 1] >> 1);
    ntt(A, lim, 1); ntt(B, lim, 1);
    for (int i = 0; i < lim; ++i)
        B[i] = 1ll * A[i] * B[i] % P;
    ntt(B, lim, -1);
    ll ans = 0;
    for (int i = 0; i <= 1e5; ++i) {
        ans = (ans + 1ll * f[i] * qpow(sqr, 1ll * i * i) % P * B[i] % P) % P;
    }
    ans = ans * 2 % P;
    for (int i = 0; i <= 1e5; ++i)
        ans = (ans - 1ll * f[i] * f[i] % P * qpow(2, 1ll * i * i) % P + P) % P;
    printf("%lld\n", (ans % P + P) % P);
}

J
相当于 i 向 p [ i ] i向p[i] ip[i]连了一条边,最后的循环次数就是环的长度的lcm
每个环的长度都是k的约数即可,枚举新加入的数i所属于的环的长度j,在剩下的i-1个数再选出j-1的排列组合数,再乘上f[i-j]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 55;
const int mod = 998244353;
/*
ll c[maxn][maxn];
ll inv[maxn], invf[maxn], f[maxn], fk[maxn][maxn];
void pre() {
    f[0] = f[1] = 1;
    inv[0] = inv[1] = 1;
    invf[0] = invf[1] = 1;
    for (int i = 2; i < maxn; ++i) {
        inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
        f[i] = 1ll * f[i - 1] * i % mod;
        invf[i] = 1ll * invf[i - 1] * inv[i] % mod;
    }
    for (int i = 1; i < maxn; ++i) {
        fk[i][0] = 1;
        for (int j = 1; j < maxn; ++j) {
            fk[i][j] = fk[i][j - 1] * inv[i] % mod;
        }
    }
    for (int i = 1; i < maxn; ++i) {
        for (int j = 0; j < maxn; ++j) {
            fk[i][j] = 1ll * fk[i][j] * invf[j] % mod;
        }
    }
}
*/

ll c[maxn][maxn], f[maxn], fac[maxn];

int main() {
    //pre();
    fac[0] = 1;
    for (int i = 1; i < maxn; ++i)
        fac[i] = fac[i - 1] * i % mod;
    for (int i = 0; i < maxn; ++i) c[i][0] = 1;
    for (int i = 1; i < maxn; ++i)
        for (int j = 1; j <= i; ++j)
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;

    ios::sync_with_stdio(false); cin.tie(0);
    int t; cin >> t;
    while (t--) {
        int n; ll k; cin >> n >> k;
        memset(f, 0, sizeof(f));
        f[0] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= i; ++j) {
                if (k % j) continue;
                f[i] = (f[i] + f[i - j] * c[i - 1][j - 1] % mod * fac[j - 1] % mod) % mod;
            }
        }
        cout << f[n] << endl;
    }
}

I
背包dp
长度为i的区间全部赋值为最大值需要 i 2 i\over2 2i次操作,相当于每个物品大小为 长 度 2 长度\over2 2,价值为该区间最大值 m a x ∗ 区 间 长 度 max*区间长度 max
d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − k ] [ j − k 2 ] + m a x ∗ k ) dp[i][j]=max(dp[i][j],dp[i-k][j-{k\over 2}]+max*k) dp[i][j]=max(dp[i][j],dp[ik][j2k]+maxk)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50 + 5;
int f[maxn][maxn];
int a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int t; cin >> t;
    while (t--) {
        int n; cin >> n;
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; ++i) cin >> a[i];
        for (int i = 1; i <= n; ++i) {
            int maxx = 0;
            for (int j = i; j >= 1; --j) {
                maxx = max(maxx, a[j]);
                int p = (i - j + 1) / 2;
                for (int k = p; k <= n; ++k)
                    f[i][k] = max(f[i][k], f[j - 1][k - p] + maxx * (i - j + 1));
            }
        }
        for (int i = 1; i <= n; ++i)
            cout << f[n][i] << (i == n ? '\n' : ' ');
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值