首页 > 其他 > 详细

UOJ22 外星人

时间:2019-11-04 17:02:03      阅读:92      评论:0      收藏:0      [点我收藏+]

题意

\(n\)个数,给出\(x\)
求出一个排列顺序,使\(n\)个数依次对\(x\)取模的最大值和方案数
$n\le 1000,x \le 5000 $
传送门

思路

终于不是一道神仙\(dp\)
考虑某个数,如果前面有数小于它,那么它存不存在都是没用的。
所以就可以从大到小考虑,分为两种:

  • 有用:那就必须紧挨着前一个\(dp[i][j\%a[i]]+=dp[i][j]\)
  • 无用:那么就要填到后面去,剩余\(n-i+1\)个,但不能在第一个,所以\(n-i\)
    \(dp[i][j]+=dp[i-1][j]*(n-i)\)

但是会出现全部选的情况,所以我就用\(0/1\)表示了前面有没有选过,好像也有不用讨论的方法
代码十分简短

#include <bits/stdc++.h>
#define upd(x,y) x=(x+y>=mu?x+y-mu:x+y)
const int N=1005,mu=998244353;
int n,x,a[N],dp[2][N][5005];
bool cmp(int x,int y){
    return x>y;
}
int main(){
    scanf("%d%d",&n,&x);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    std::sort(a+1,a+n+1,cmp);
    dp[0][0][x]=1;
    for (int i=1;i<=n;i++)
        for (int j=0;j<=x;j++){
            upd(dp[1][i][j%a[i]],dp[0][i-1][j]);//选 
            upd(dp[1][i][j%a[i]],dp[1][i-1][j]);
            upd(dp[1][i][j],dp[1][i-1][j]*1ll*(n-i)%mu);//不选 
            upd(dp[0][i][j],dp[0][i-1][j]*1ll*(n-i)%mu);
        } 
    for (int j=x;j>=0;j--){
        if (dp[1][n][j]){
            printf("%d\n%d\n",j,dp[1][n][j]);
            return 0;
        }
    }
} 

后记

难得的开心水题

UOJ22 外星人

原文:https://www.cnblogs.com/flyfeather6/p/11792645.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!