uoj22 【UR #1】外星人

link

 

题意:

给一个长为n的序列a[],现在有一个初始值m,问一个1~n的排列p[],满足将m对a[p[i]]顺次取模后得到的值最大,输出最大值和方案数。

$n,m\leq 5\times 10^3.$

 

题解:

如果存在i,j满足i<j&&a[i]<a[j],那么这个a[j]是没有用的,取不取模效果一样。

考虑将a[]从大到小排序,原问题转化为从左往右选择若干个数取模,所得的最大值以及方案数。定义f[i][j]表示操作到前i个数%之后值为j的方案数。

考虑转移,我们从小到大加数:

如果当前数取模,那么这个数的位置唯一(放在n-i个数之前);否则这个数可以放在n-i个数的任意一个空之间,n-i种方案。

复杂度$\mathcal{O}(n\times m).$

 

code:

 1 #include<bits/stdc++.h>
 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++)
 3 #define per(i,x,y) for (int i=(x);i>=(y);i--)
 4 #define ll long long
 5 #define inf 1000000001
 6 #define y1 y1___
 7 using namespace std;
 8 char gc(){
 9     static char buf[100000],*p1=buf,*p2=buf;
10     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
11 }
12 #define gc getchar
13 ll read(){
14     char ch=gc();ll x=0;int op=1;
15     for (;!isdigit(ch);ch=gc()) if (ch=='-') op=-1;
16     for (;isdigit(ch);ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
17     return x*op;
18 }
19 #define N 5005
20 #define mod 998244353
21 int n,m,a[N],f[N][N];
22 void upd(int &x,int y){x+=y;x-=x>=mod?mod:0;}
23 int main(){
24     n=read(),m=read();
25     rep (i,1,n) a[i]=read();
26     sort(&a[1],&a[n+1],greater<int>());
27     f[0][m]=1;
28     rep (i,1,n) rep (j,0,m) if (f[i-1][j]){
29         upd(f[i][j],(ll)(n-i)*f[i-1][j]%mod);
30         upd(f[i][j%a[i]],f[i-1][j]);
31     }
32     per (i,a[n]-1,0) if (f[n][i]) return printf("%d\n%d\n",i,f[n][i]),0;
33     return 0;
34 }
View Code

 

posted @ 2018-07-25 23:54  bestfy  阅读(214)  评论(2编辑  收藏  举报