uoj22 【UR #1】外星人

时间:2023-03-10 03:50:45
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:

 #include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define per(i,x,y) for (int i=(x);i>=(y);i--)
#define ll long long
#define inf 1000000001
#define y1 y1___
using namespace std;
char gc(){
static char buf[],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
ll read(){
char ch=gc();ll x=;int op=;
for (;!isdigit(ch);ch=gc()) if (ch=='-') op=-;
for (;isdigit(ch);ch=gc()) x=(x<<)+(x<<)+ch-'';
return x*op;
}
#define N 5005
#define mod 998244353
int n,m,a[N],f[N][N];
void upd(int &x,int y){x+=y;x-=x>=mod?mod:;}
int main(){
n=read(),m=read();
rep (i,,n) a[i]=read();
sort(&a[],&a[n+],greater<int>());
f[][m]=;
rep (i,,n) rep (j,,m) if (f[i-][j]){
upd(f[i][j],(ll)(n-i)*f[i-][j]%mod);
upd(f[i][j%a[i]],f[i-][j]);
}
per (i,a[n]-,) if (f[n][i]) return printf("%d\n%d\n",i,f[n][i]),;
return ;
}