题意:给你一个数列ai,设d经过a的一个排列顺次对ai取模最后得到y。
求使得|d-y|最小的y,以及可以达到y的排列数%998244353。
ai,x<=5000,n<=1000.
标程:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 const int mod=998244353; 6 const int N=1005; 7 int n,d,f[N][N*5],a[N]; 8 bool cmp(int A,int B){return A>B;} 9 int main() 10 { 11 scanf("%d%d",&n,&d); 12 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 13 sort(a+1,a+n+1,cmp); 14 f[0][d]=1; 15 for (int i=1;i<=n;i++) 16 { 17 for (int j=0;j<=d;j++) f[i][j]=((ll)f[i][j]+(ll)f[i-1][j]*(n-i)%mod)%mod;//注意j有可能等于d。 18 for (int j=0;j<=d;j++) f[i][j%a[i]]=((ll)f[i][j%a[i]]+f[i-1][j])%mod; 19 } 20 for (int i=a[n]-1;i>=0;i--) if (f[n][i]) return printf("%d\n%d\n",i,f[n][i]),0; 21 }
题解:dp
分析后可以发现,如果排列中一个ai前面有aj比它小,那么这个ai就是无用的。
反之,如果前面所有的aj都比ai大,那么ai就是关键点。
先把所有元素从大到小排序。
我们将元素从小到大加入,设当前加入的数是ai。那么之后的n-i个都已经加入,并且都比ai要小。那么ai是关键点当且仅当ai插入在全部n-i个小于ai的点之前。反之ai有n-i个间隔可插入且不是关键点。
设f[i][j]为%前i个数(从大到小排序的前i个)后余数为j的方案数。
1.ai作为关键点:f[i][j%a[i]]+=f[i-1][j];经过前i-1个数后对ai取模。
2.ai为非关键点:f[i][j]+=(n-i)*f[i-1][j]。有n-i个间隔可供插入,这个点无效就不必考虑。
时间复杂度O(nd)。