zoukankan      html  css  js  c++  java
  • Luogu P6300 悔改

    link

    题解

    (f_x) 表示组成 (x) 的个数,(b_i) 表示长度为 (i) 的木棍的出现次数。则 (f_x = leftlfloordfrac{1}{2}sumlimits_{i=1}^x min{b_i,b_{x-i}} ight floor = leftlfloordfrac{1}{2}sumlimits_{i=1}^x sumlimits_{k=1}^n[b_igeq k][b_{x-i}geq k] ight floor = leftlfloordfrac{1}{2}sumlimits_{k=1}^nsumlimits_{i=1}^x [b_igeq k][b_{x-i}geq k] ight floor)
    然后就可以跑 (m) 次 NTT,时间复杂度为 (O(nmlog m))
    考虑不同的 (a) 数量不超过 (sqrt n),所以可以离散化之后再做,时间复杂度为 (O(sqrt n mlog m))

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define MAX_N (100000 + 5)
    #define MAX_M (100000 + 5)
    #define G 3
    #define mod 998244353
    #define LL long long
    using std::swap;
    using std::sort;
    using std::unique;
    using std::lower_bound;
    int n, m, N, invN, invG;
    int a[MAX_M], b[MAX_N];
    int f[MAX_M << 2], pos[MAX_N << 2];
    int ans[MAX_M << 1];
    void Read(int &x) {
    	x = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    }
    int Pow(int x, int y) {
    	int res = 1;
    	for (; y; y >>= 1, x = (LL)x * x % mod) if (y & 1) res = (LL)res * x % mod;
    	return res;
    }
    void NTT(int *f, bool is) {
    	for (int i = 0; i < N; ++i) if (i < pos[i]) swap(f[i], f[pos[i]]);
    	int w, cur, res;
    	for (int k = 2, mid = 1; k <= N; k <<= 1, mid <<= 1) {
    		if (is) w = Pow(invG, (mod - 1) / k);
    		else w = Pow(G, (mod - 1) / k);
    		for (int i = 0; i < N; i += k) {
    			cur = 1;
    			for (int j = i; j < i + mid; ++j, cur = (LL)cur * w % mod) {
    				res = (LL)cur * f[j + mid] % mod;
    				f[j + mid] = f[j] - res;
    				if (f[j + mid] < 0) f[j + mid] += mod;
    				f[j] = f[j] + res;
    				if (f[j] >= mod) f[j] -= mod;
    			}
    		}
    	}
    	if (is) for (int i = 0; i < N; ++i) f[i] = (LL)f[i] * invN % mod;
    }
    int main() {
    	Read(n), Read(m);
    	int x, cnt = 0;
    	for (int i = 1; i <= n; ++i) Read(x), ++a[x];
    	for (int i = 1; i <= m; ++i) b[++cnt] = a[i];
    	b[++cnt] = 0;
    	sort(b + 1, b + cnt + 1);
    	cnt = unique(b + 1, b + cnt + 1) - b - 1;
    	for (int i = 1; i <= m; ++i) a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b;
    	for (N = 1; N <= m + m; N <<= 1);
    	invN = Pow(N, mod - 2), invG = Pow(G, mod - 2);
    	for (int i = 1; i < N; ++i) pos[i] = pos[i >> 1] >> 1 | (i & 1 ? N >> 1 : 0);
    	for (int k = 2; k <= cnt; ++k) {
    		memset(f, 0, sizeof f);
    		for (int i = 0; i <= m; ++i) f[i] = a[i] >= k ? 1 : 0;
    		NTT(f, 0);
    		for (int i = 0; i < N; ++i) f[i] = (LL)f[i] * f[i] % mod;
    		NTT(f, 1); 
    		for (int i = 1; i <= m + m; ++i) ans[i] += f[i] * (b[k] - b[k - 1]);
    	}
    	for (int i = 1; i <= m + m; ++i) ans[i] >>= 1;
    	int Ans = 0;
    	for (int i = 1; i <= m + m; ++i) if (ans[i] > ans[Ans]) Ans = i;
    	printf("%d %d", ans[Ans], Ans);
    	return 0;
    }
    

    当然也可以根号分治做,个人以为没必要。

  • 相关阅读:
    uC/OS-II时间(OS_time)块
    uC/OS-II任务(OS_task)块
    uC/OS-II信号(OS_sem)块
    uC/OS-II队列(OS_q)块
    uC/OS-II互斥信号(OS_mutex)块
    uC/OS-II内存(OS_mem)块
    elasticsearch-installation
    rabbitmq的安装
    str_翻转字符串
    str_2.判断两个字符串是否互为旋转词
  • 原文地址:https://www.cnblogs.com/kcn999/p/14141048.html
Copyright © 2011-2022 走看看