zoukankan      html  css  js  c++  java
  • UOJ22 外星人

    题意

    (n)个数,给出(x)
    求出一个排列顺序,使(n)个数依次对(x)取模的最大值和方案数
    $nle 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
    %d
    ",j,dp[1][n][j]);
    			return 0;
    		}
    	}
    } 
    

    后记

    难得的开心水题

  • 相关阅读:
    坐标转换convertRect
    error this is not a media message!!!
    嵌入式-第一季-第4课
    嵌入式-第一季-第2课
    嵌入式-第一季-第3课
    嵌入式-第一季-第1课
    web-15. 事件与函数
    web-14. 表达式与程序流程
    web-13. 数组和字符串
    数据-第5课-线性表的本质
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11792645.html
Copyright © 2011-2022 走看看