题意:
给一个长为n的序列a[],现在有一个初始值m,问一个1~n的排列p[],满足将m对a[p[i]]顺次取模后得到的值最大,输出最大值和方案数。
$n,mleq 5 imes 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 imes 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 %d ",i,f[n][i]),0; 33 return 0; 34 }