• CF1188C Array Beauty 题解


    Codeforces
    Luogu

    Description.

    一个序列的权值定义为其中任意两个数之间绝对值的最小值。
    计算所有长度为 \(k\) 的子序列权值之和 \(\text{mod}\ 998244353\)

    Solution.

    感觉到了是个 dp,没想到要去枚举答案和差分

    首先,答案范围是 \(\frac{V}k\) 所以我们枚举答案算数量
    但是,答案恰好为 \(x\) 的也很难算,所以我们考虑差分,算出答案 \(\ge x\) 的方案数
    设计一个 \(dp_{i,j}\) 表示当前第 \(i\) 位,选出了 \(j\) 个的方案数
    \(dp[i][j]=dp[k][j-1]\) 之和,然后刚好可以双指针+前缀和维护
    需要满足 \(a[i]-a[k]>=lim\)
    复杂度是 \(O(\frac Vk\times k\times n)=O(V\times n)\) 可过

    Coding.

    点击查看弱鸡代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }/*}}}*/
    const int P=998244353;
    int n,K,a[1005],mx=0,rs[100005],dp[1005][1005],sm[1005][1005];
    inline void solve(int lim)
    {
    	dp[0][0]=1;for(int i=0;i<=n;i++) sm[0][i]=1;
    	for(int j=1;j<=K;j++)
    	{
    		int it=0;for(int i=1;i<=n;i++)
    		{
    			while(a[i]-a[it+1]>=lim) it++;
    			dp[j][i]=sm[j-1][it];
    		}
    		//for(int i=1;i<=n;i++) printf("%d%c",dp[j][i],i==n?'\n':' ');
    		for(int i=1;i<=n;i++) sm[j][i]=(sm[j][i-1]+dp[j][i])%P;
    	}
    	for(int i=1;i<=n;i++) rs[lim]=(rs[lim]+dp[K][i])%P;
    	//printf("%d : %d\n",lim,rs[lim]);
    }
    int main()
    {
    	read(n),read(K);for(int i=1;i<=n;i++) read(a[i]),mx=max(mx,a[i]);
    	int L=mx/(K-1);sort(a+1,a+n+1),a[n+1]=1e9;for(int i=1;i<=L;i++) solve(i);
    	for(int i=1;i<=L;i++) rs[i]=(rs[i]-rs[i+1]+P)%P;
    	int ans=0;for(int i=1;i<=mx/(K-1);i++) ans=(ans+1ll*i*rs[i])%P;
    	return printf("%d\n",ans),0;
    }
    
  • 相关阅读:
    java跳过构造方法新建对象
    java实现类似qq的窗口对聊
    NoSql的产生
    C语言跳出循环
    C语言for循环
    C语言while语句
    C语言条件运算符
    C语言switch语句
    C语言逻辑运算符
    C语言关系运算符
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15045996.html
Copyright © 2020-2023  润新知