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;
    		}
    	}
    } 
    

    后记

    难得的开心水题

  • 相关阅读:
    uva-11361
    HDU
    LCS
    CodeForces
    linux 有趣的命令组合
    opencv识别封闭区域 并标记该区域
    宜出行人口热力图
    美团酒店
    赶集租房
    发送企业微信应用通知
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11792645.html
Copyright © 2011-2022 走看看