【A、韩信点兵】
结论题+模板题,用到了中国剩余定理,维基百科上讲的就比较详细,这里就不再赘述了……
对于这题,我们先利用中国剩余定理($x equiv sum{(a_i m_i (m_i^{-1} mod p_i))}\, mod (prod{p_i})$)找到当前人数的最小可行解$x_0$,(如果$x_0$已经超过了$N$,直接输出无解即可)这时不难证明,对于任何一个可行解,都有 $$x_i = x_0 + k imes prod{P_i},k in mathbb{N}$$
我们的目标是找到不超过$N$的最大可行解x',那么答案就是$N - x'$。注意这里如果直接枚举$k$的话有一个测试点会超时(看起来我的数据规模还是挺良心的……只卡掉了10分)。正确的做法是先用$N$减去$x_0$,这时剩下的部分就是$N - x' + k imes prod{P_i},k in mathbb{N}$,那么我们只需用这个结果对$prod{P_i}$取余即可得到答案。
2 #include <cctype>
3 #include <algorithm>
4 #include <cstring>
5 #include <queue>
6 #include <cmath>
7 #include <iostream>
8
9
10 typedef long long LL;
11 using namespace std;
12 inline int lowbit(int x){return x & -x;}
13 int gcd(int a, int b){return (!a) ? b : gcd(b % a, b);}
14 template<typename T>T exgcd(T a, T b, T &x, T &y){
15 if(!a){x = 0, y = 1; return b;}
16 T d = exgcd(b % a, a, y, x);
17 x -= (b/a) * y;
18 return d;
19 }
20 /*=====================================*/
21 inline LL inv(LL a, LL mod){
22 LL x, y;
23 if(exgcd(a, mod, x, y) != 1)return -1;
24 return (x % mod + mod) % mod;
25 }
26 LL n, M = 1, N[11], e, S = 0;
27 int P[11], a[11], m;
28
29 inline void init(){
30 cin >> n >> m;
31 for(int i = 0;i < m;++i){
32 cin >> P[i] >> a[i];
33 M *= P[i];
34 }
35 for(int i = 0;i < m;++i){
36 N[i] = M / P[i];
37 e = N[i] * inv(N[i], P[i]) % M;
38 S = (S + e * a[i]) % M;
39 }
40 }
41
42 inline void work(){
43 LL x, y;
44 exgcd<LL>(1, M, x, y);
45 x = ((x * S % M) + M ) % M;
46 if(x > n){cout << -1 << endl;return;}
47 cout << (n - x) % M << endl;
48 }
49
50 int main(){
51 #if defined DEBUG
52 freopen("test", "r", stdin);
53 #else
54 freopen("HanXin.in", "r", stdin);
55 freopen("HanXin.out", "w", stdout);
56 #endif
57
58 init();
59
60 work();
61
62 return 0;
63 }
【B、月考统计】
经典模型——差分约束系统。设第i位同学的分数为$x_i$,所有同学的最低分数为0. 则统计表中的每条息$i,j,a_{ij}$都可以形式化为 $$x_i - x_j le a_{ij}$$。
对于这样一组不等式,我们可以抽象化出图论模型:每个同学都抽象为一个节点,再设一个起点0,表示所有同学的最低分数。对于每个不等式$x_i - x_j le a_{ij}$,我们都从点i到点j连一条权值为$-a_{ij}$的有向边,表示从起点到点j的最长路权和最少比起点到i的最长路权和大$-a_{ij}$(可以用最长路的三角形不等式证明)。对于这样的图,用spfa求出从起点到每个点的最长路权和就是答案。
2 /*======================================================Code by Asm.Def========================================================*/
3 /*=============================================================================================================================*/
4 #include <cstdio>
5 #include <iostream>
6 #include <algorithm>
7 #include <cmath>
8 #include <cctype>
9 #include <memory.h>
10 #include <vector>
11 #include <set>
12 #include <string>
13 #include <cstring>
14 #include <map>
15 #include <queue>
16 #include <deque>
17 #include <stack>
18 #include <ctime>
19 #include <iterator>
20 #include <functional>
21 #include <cstdlib>
22 using namespace std;
23 /*===================================================================================*/
24 #define forall(it,v) for(__typeof(v.begin()) it = v.begin();it < v.end();++it)
25 #define pb push_back
26 #define REP(i,j,k) for(i = j;i <= k;++i)
27 #define REPD(i,j,k) for(i = j;i >= k;--i)
28 #define iter(v) v::iterator
29 typedef long long LL;
30 template<typename T> void getint(T &x){
31 char c = getchar();
32 while(!isdigit(c))c = getchar();
33 x = c - '0';
34 while(isdigit(c = getchar()))x = x * 10 + c - '0';
35 }
36 /*============================================================================================*/
37 const int maxn = 2000 + 5;
38 int N, M;
39 struct edge{
40 int to, w;
41 edge(int T, int W):to(T), w(W){}
42 };
43 vector<edge> adj[maxn];
44
45 queue<int> Q;
46 bool inQ[maxn] = {0};
47 int dis[maxn] = {0}, cnt[maxn] = {0};
48 inline void init(){
49 cin >> N >> M;
50 int i, x, y, a;
51 while(M--){
52 cin >> x >> y >> a;
53 adj[x].push_back(edge(y, -a));
54 }
55 for(i = 1;i <= N;++i)
56 Q.push(i);inQ[i] = 1;cnt[i] = 1;
57 }
58 inline void work(){
59 int i, t;
60 iter(vector<edge>) it;
61 while(!Q.empty()){
62 t = Q.front();Q.pop();inQ[t] = 0;
63 for(it = adj[t].begin();it != adj[t].end();++it)
64 if(dis[t] + it->w > dis[it->to]){
65 dis[it->to] = dis[t] + it->w;
66 if(!inQ[it->to]){
67 if(cnt[it->to] == N){
68 cout << "SOMEONE LAY!" << endl;
69 return;
70 }
71 Q.push(it->to);inQ[it->to] = 1;++cnt[it->to];
72 }
73 }
74 }
75 for(i = 1;i <= N;++i)
76 cout << dis[i] << ' ';
77 }
78
79 int main(){
80 #ifdef DEBUG
81 freopen("test", "r", stdin);
82 #else
83 freopen("ExamStat.in", "r", stdin);
84 freopen("ExamStat.out", "w", stdout);
85 #endif
86
87 init();
88 work();
89
90 #ifdef DEBUG
91 //cout << endl << (double)clock() / CLOCKS_PER_SEC <<endl;
92 #endif
93 return 0;
94 }
【C、神奇的压缩机】
神奇的压缩机,神奇的阅读题……
这题改编自第21场Andrew Stankevich's Contest(俄国的ACM多校训练赛)的Lempel-Ziv Compression……
当时我的解法是预处理出字符串中每个子串的“满足i小于子串长度且i前缀与i后缀相等的i”的最大值(或 原串的每个后缀的KMP-next数组)……听起来相当拗口,不过套用KMP的预处理过程可以降低思维难度。
2 // Submission Date: 2014-10-02 16:34:32
3 // Time: 8256MS
4 // Memory: 34624KB
5
6 /*======================================================Code by Asm.Def========================================================*/
7 #include <cstdio>
8 #include <iostream>
9 #include <algorithm>
10 #include <cmath>
11 #include <cctype>
12 #include <memory.h>
13 #include <cstring>
14 #include <cstdlib>
15 using namespace std;
16 #define maxn ((int)4.1e3)
17
18 typedef long long LL;
19
20 char ch[maxn];
21 int len = 0, minbit[maxn], *next[maxn];
22 int l[maxn], r[maxn], str[maxn];
23
24
25 inline void getnext(int l){
26 int i, j, L = len - l;
27 next[l] = new int[L+2];
28 int *Next = next[l];
29 Next[0] = 0;
30 for(i = 1;i < L;++i){
31 j = Next[i-1] - 1;
32 while(ch[l+i] != ch[l+j+1] && j >= 0)
33 j = Next[j] - 1;
34 if(ch[l+i] == ch[l+j+1])
35 Next[i] = j + 2;
36 else Next[i] = 0;
37 }
38 }
39 void printpro(int i){
40 if(str[i] == i){
41 if(r[i])printpro(r[i]-1);
42 int j;
43 for(j = r[i];j <= i;++j)putchar(ch[j]);
44 return;
45 }
46 printpro(str[i]);
47 printf("(%d,%d)", r[i], l[i]);
48 }
49 int main(){
50 #ifdef DEBUG
51 assert(freopen("test","r",stdin));
52 #endif
53
54 char c;
55 while(isalpha(c = getchar()))str[len] = len, ch[len++] = c;
56 int i, j, Min, t;
57 for(i = 0;i < len - 1; ++i)
58 getnext(i);
59 minbit[0] = 9;
60 for(i = 1;i < len; ++i){
61 Min = 0x7fffffff;
62 for(j = 0;j < i;++j)
63 if(minbit[j] + (i-j)*9 < Min){
64 Min = minbit[j] + (i-j)*9;
65 str[i] = i;
66 r[i] = j+1;
67 }
68 for(j = 0;j < i; ++j){
69 t = next[j][i-j];
70 if(!t)continue;
71 if(minbit[i-t] + 25 < Min){
72 Min = minbit[i-t] + 25;
73 str[i] = i-t;
74 r[i] = i+1-t-j;
75 l[i] = t;
76 }
77 }
78 minbit[i] = Min;
79 }
80 printf("%d ", minbit[len-1]);
81 printpro(len-1);
82 return 0;
83 }