AtCoder Beginner Contest 262 D - I Hate Non-integer Number

AtCoder Beginner Contest 262

D - I Hate Non-integer Number

题意

给你一个长度为 n n n的数组,问:从数组中选择任意个 元素,这些元素的平均数为整数的方案数为多少。

数据范围

1 ⩽ n ⩽ 100 1 \leqslant n \leqslant 100 1n100
思路

本题考察 动态规划

我们令 d p [ j ] [ k ] [ l ] dp[j][k][l] dp[j][k][l]为在长度为 i i i的情况下,数组中前 j j j个元素中选择 k k k个元素 m o d mod mod % i \%i %i l l l的方案数。
那么答案就是
∑ i = 1 n d p [ n ] [ i ] [ 0 ] \sum_{i = 1}^{n} dp[n][i][0] i=1ndp[n][i][0]

转移:我们可以考虑第 j j j个数是否选择来进行转移
d p [ j ] [ k ] [ l ] = { d p [ j − 1 ] [ k ] [ l ] ( 不选 ) d p [ j − 1 ] [ k − 1 ] [ l − ( a [ j ]   %   i ) ] ( a [ j ]   %   i   ⩾   0 ) d p [ j − 1 ] [ k − 1 ] [ i + l − ( a [ j ]   %   i ) ] ( a [ j ]   %   i < 0 ) dp[j][k][l] = \begin{cases}dp[j - 1][k][l]\quad(不选)\\ dp[j - 1][k - 1][l - (a[j]\ \% \ i)] \quad(a[j] \ \%\ i\ \geqslant\ 0)\\ dp[j - 1][k - 1][i + l - (a[j] \ \% \ i)]\quad (a[j]\ \% \ i< 0)\end{cases} dp[j][k][l]= dp[j1][k][l](不选)dp[j1][k1][l(a[j] % i)](a[j] % i  0)dp[j1][k1][i+l(a[j] % i)](a[j] % i<0)

初始化:
d p [ 0 ] [ 0 ] [ 0 ] = 1 dp[0][0][0] = 1 dp[0][0][0]=1

时间复杂度

O ( N 4 ) O(N^4) O(N4)

代码

#include <bits/stdc++.h>
#define PII pair<int,int>
#define LL long long
#define fi first
#define se second
#define debug(a) cout<<#a<<"="<<a<<endl;
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define Yes puts("Yes");
#define No puts("No");
#define sz(x) (int)x.size()
using namespace std;
inline string rd()
{
    string str="";
    char ch=getchar();
    while(ch==' ' || ch=='\n' || ch=='\r')
    {
        ch=getchar(); 
    }
    while(ch!=' ' && ch!='\n' && ch!='\r')
    {
        str+=ch;
        ch=getchar();
     } 
    return str;
}
inline void print(string s)
{
    for(int i=0; s[i]!='\0'; i++) putchar(s[i]);
}
template <typename T> void read(T &t) {
    t=0; char ch=getchar(); int f=1;
    while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
    do { (t*=10)+=ch-'0'; ch=getchar(); } while ('0'<=ch&&ch<='9'); t*=f;
}
template <typename T> void write(T t) {
    if (t<0) { putchar('-'); write(-t); return; }
    if (t>9) write(t/10);
    putchar('0'+t%10);
}
template <typename T> void writeln(T t) { write(t); puts(""); }
const int N = 110, mod = 998244353;
int a[N], n;
LL dp[N][N][N];//dp[j][k][l]表示前j个数选则k个数的和modi为l的方案数
int main()
{
    read(n);
    LL sum = 0;
    for(int i = 1; i <= n; i ++ ) read(a[i]);
    for(int i = 1; i <= n; i ++ ){//一共选i个数  O(N^4)
        dp[0][0][0] = 1;
        for(int j = 1; j <= n; j ++ ){
            for(int k = 0; k <= j; k ++ ){
                for(int l = 0; l < i; l ++ ){
                    // 不选的方案数
                    dp[j][k][l] = (dp[j][k][l] + dp[j - 1][k][l]) % mod;
                    // 选的方案数
                    int x = a[j] % i;
                    if(k >= 1){
                        if(l - x >= 0) dp[j][k][l] = (dp[j][k][l] + dp[j - 1][k - 1][l - x]) % mod;
                        else dp[j][k][l] = (dp[j][k][l] + dp[j - 1][k - 1][i + l - x]) % mod;                       
                    }
                }
            }
        }
        sum += dp[n][i][0];
        sum %= mod;
        memset(dp, 0, sizeof dp);
    }
    printf("%lld\n",sum);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值