#22. 【UR #1】外星人

                                             #22. 【UR #1】外星人

2044年,Picks建成了人类第一台基于量子理论的银河系信息传递机。

Picks游遍了宇宙,雇用了 nn 个外星人来帮他作为信息传递机的中转站。我们将外星人依次编号为 11 到 nn,其中 ii 号外星人有 aiai 根手指。

外星人都是很低级的,于是Picks花费了很大的精力,才教会他们学会扳手指数数。

Picks现在准备传递 xx 个脉冲信号给VFleaKing,于是他把信号发给11号外星人,然后11号外星人把信号发送给22号外星人,22号外星人把信号发送给33号外星人,依次类推,最后nn号外星人把信号发给VFleaKing。

但是事情没有Picks想象的那么顺利,由于外星人手指个数有限,所以如果 ii 号外星人收到了 tt 个脉冲信号,他会错误的以为发送过来的是 tmodaitmodai 个脉冲信号,导致只发送了 tmodaitmodai 个脉冲信号出去。

Picks希望他发送出去的脉冲信号数量 xx 与VFleaKing收到的脉冲信号数量 yy 的差的绝对值尽量小。于是他决定通过重新排列这些外星人的顺序来达到这一目的。请你求出与 xx 之差最小的 yy。除此之外,请求出有多少种排列外星人的方式能达到最优解,你只需要输出方案数对 998244353998244353(7×17×223+17×17×223+1,一个质数)取模后的结果。

输入格式

第一行两个正整数n,xn,x。

接下来一行有 nn 个正整数 aiai,表示 ii 号外星人的手指数。

输出格式

第一行一个整数表示最优情况下VFleaKing收到的脉冲数量。

第二行一个整数表示达到最优情况的方案数。

样例一

input

2 15
7 10

output

5
1

explanation

共两种可行方案:

  1. 15mod7=115mod7=1,1mod10=11mod10=1
  2. 15mod10=515mod10=5,5mod7=55mod7=5

显然第二种方案更优。

样例二

input

7 33
2 4 6 8 16 16 32

output

1
5040

explanation

每个排列方案都是最优解。

样例三

见样例数据下载

限制与约定

对于每个测试点,答对第一问可获得 40% 的分数,答对第二问可获得 60% 的分数。

请注意你必须输出两个整数否则会判0分。假如你只做了第一问,那么你应该输出你第一问的答案,然后再随便输出一个第二问的答案。

测试点编号nn的规模xx 和 aiai的规模
1 n10n≤10 x,ai20x,ai≤20
2 n50n≤50 x,ai100x,ai≤100
3
4 n100n≤100 x,ai500x,ai≤500
5
6
7 n1000n≤1000 x,ai5000x,ai≤5000
8
9
10

时间限制:1s1s

空间限制:256MB

 

详解

f[i][j]代表 处理a[i] 能否得到 j 

g[i][j] 记录方案数 

考虑取模运算。一个非常基础的性质是:当 xai 时,mod ai<ai。当 ai 时,mod ai=

那么对于每个ai,要么就把它放在当前位置,现在生效,要么把它放在后面的ni个位置,使它永不生效,因为如果你先模了一个小于ai的数,再模ai结果是不会变的。

 

 1 #include <cstdio>
 2 #include <cctype>
 3 #include <algorithm>
 4 
 5 typedef long long LL;
 6 
 7 const int mod=998244353;
 8 const int MAXN=1010;
 9 const int MAXM=5010;
10 
11 int n,s;
12 
13 int a[MAXM];
14 
15 bool f[MAXN][MAXM];
16 
17 LL g[MAXN][MAXM];
18 
19 inline bool cmp(int a,int b) {return a>b;}
20 
21 inline void read(int&x) {
22     int f=1;register char c=getchar();
23     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
24     for(;isdigit(c);x=x*10+c-48,c=getchar());
25     x=x*f;
26 }
27 
28 inline void running() {
29     f[0][s]=1;g[0][s]=1;
30     for(int i=1;i<=n;++i) {
31         for(int j=s;j>=0;--j) {
32               f[i][j%a[i]]|=f[i-1][j];
33               g[i][j%a[i]]=(g[i][j%a[i]]+g[i-1][j])%mod;
34         }
35         if(i!=n) {
36             for(int j=s;j>=0;--j) {
37                 f[i][j]|=f[i-1][j];
38                 g[i][j]=(g[i][j]+g[i-1][j]*(n-i))%mod;
39             }
40         }
41     }
42     for(int i=s;i>=0;--i)
43       if(f[n][i]) {
44           printf("%d\n",i);
45           printf("%lld\n",g[n][i]);
46           break;
47       }
48     return;
49 }
50 
51 int hh() {
52     read(n);read(s);
53     for(int i=1;i<=n;++i) read(a[i]);
54     std::sort(a+1,a+1+n,cmp);
55     running();
56     return 0;
57 }
58 
59 int sb=hh();
60 int main(int argc,char**argv) {;}
代码

 

posted @ 2017-09-11 21:57  拿叉插猹哈  阅读(327)  评论(0编辑  收藏  举报