NOIP模拟·20141105题解

A、韩信点兵

结论题+模板题,用到了中国剩余定理,维基百科上讲的就比较详细,这里就不再赘述了……

对于这题,我们先利用中国剩余定理($x \equiv \sum{a_i \times m_i (m_i^{-1} \mod p_i)}\, \mod (\prod{p_i})$)找到当前人数的最小可行解$x_0$,(如果$x_0$已经超过了$N$,直接输出无解即可)这时不难证明,对于任何一个可行解,都有 $$x_i = x_0 + k \times \prod{P_i},k \in \mathbb{N}$$

我们的目标是找到不超过$N$的最大可行解x‘,那么答案就是$N - x‘$。注意这里如果直接枚举$k$的话有一个测试点会超时(看起来我的数据规模还是挺良心的……只卡掉了10分)。正确的做法是先用$N$减去$x_0$,这时剩下的部分就是$N - x‘ +

k \times \prod{P_i},k \in \mathbb{N}$,那么我们只需用这个结果对$\prod{P_i}$取余即可得到答案。

1 #include <cstdio>
 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求出从起点到每个点的最长路权和就是答案。

1 /*=============================================================================================================================*/
 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 }

spfa解差分约束

C、神奇的压缩机

神奇的压缩机,神奇的阅读题……

这题改编自第21场Andrew Stankevich‘s Contest(俄国的ACM多校训练赛)的Lempel-Ziv Compression……

当时我的解法是预处理出字符串中每个子串的“满足i小于子串长度且i前缀与i后缀相等的i”的最大值(或 原串的每个后缀的KMP-next数组)……听起来相当拗口,不过套用KMP的预处理过程可以降低思维难度。

1 //Verdict: Accepted 2 
 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\n", minbit[len-1]);
81     printpro(len-1);
82     return 0;
83 }

动态规划

时间: 2024-10-16 09:25:51

NOIP模拟·20141105题解的相关文章

NOIP模拟 8-21 题解

一份模拟题...水得要命真是没谁了. 减法 (sub.c/.cpp) 题目描述 东东在幼儿园刚刚学会了 20 以内的减法,就迫不及待的跑回家要给爸爸出题了.问“10-1”来考东东爸,东东爸想也没想就说是“1”.东东顿时喜笑颜开,臭爸爸连这都不知道.那你知道为啥么?嘻嘻,当然这不是题目了. 这回换东东爸出题了: 两个整数 A 和 B,问 A-B 的结果是多少. 其中 1<=A<=101000, 0<=B<=A. 东东一脸懵圈,说:“臭爸爸,我不会,你告诉我结果吧.“ 这回轮到东东爸懵

NOIP模拟21题解

Contents Contents 六元组 Description Input Output 数据范围与约定 Solution 牛排序 Description Input Output 样例解释 Solution Step1 Step2 Step3 Step4 打砖块 Description Input Output 数据范围与约定 Solution 1.六元组 (six.c/.cpp/.pas) Description 有n个整数,现在想知道有多少个六元组(a,b,c,d,e,f) 满足:(a

liu_runda 给辣鸡蒟蒻做的 NOIP模拟赛 1.0 第二题 任(duty) 题解

问题 B: 任(duty) 时间限制: 2 Sec  内存限制: 512 MB 题目描述 liu_runda退役之后就失去梦想开始咸鱼生活了- Bilibili夏日画板活动中,所有人都可以在一块画板上进行像素画创作.UOJ群有一群无聊的人决定在画板上创作一个50*50的UOJ的LOGO.如下图. 这块画板实际上是很大的矩形网格.一个网格是一像素. 一个人每三分钟才能画一个像素.所以liu_runda的咸鱼生活非常无聊. 郭神表示他实在是看不下去liu_rudna这只颓狗了,于是随手出了一道神题,

NOIP模拟17.8.17

NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 k 种字母.要求满足:• 字符串中相邻的两个字母不能相同.• 必须出现恰好 k 种不同的字母.这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个.小 G 太笨啦,不会做这道题,希望你帮帮他.[输入格

NOIP模拟 17.8.18

NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也需要一定量的草作为饲料对于第 i头奶牛来说,它每天可以产 vi升的奶,同时需要 wi千克的草作为饲料现在来自蚯蚓国的九条可怜想借一些奶牛,使借走的这些奶牛每天的总产奶量最大,但九条可怜很穷,每天最多只能提供W千克的草作为饲料,而且她还需要对付跳蚤国的神刀手,所以她把这个问题交给了阿强巴,不不不……阿

NOIP模拟17.9.21

NOIP模拟17.9.21 1 任务安排manage.in/.out/.cpp1.1 问题描述你有N 个工作,同一时刻只能做一个任务, 其中每个工作有其所需时间, 及完成的Deadline(截止时间), 问要完成所有工作, 最迟要从什么时候开始.你最早可以从时间0 开始工作.1.2 输入格式第一行一个整数N,表示任务数量接下来n 行,每行两个整数,Ti; Si,分别表示该任务的持续时间和截止时间.1.3 输出格式输出一个整数,表示最晚的开始时间,如果不能完成,输出-1.1.4 样例输入43 58

NOIP模拟17.9.22

NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥ ??的位置去,但很不幸数轴上有??个区间是禁区,不能进入.青蛙会选择一个长度??,从原点开始每次向右跳长度为??的一段.一路上青蛙会停的位置是0, ??, 2??,…直到跳到了≥ ??的位置,任意一个位置都不能在禁区中.请求出??的最小值,注意??可以是实数.[输入格式]输入文件为susume.in.输入文件的第一行包含两个整数??和??,含义如问题描述中所述.接下来??行,每行描述一个禁区.每行有两个整数

noip模拟测试21

T1:折纸 这道写崩我也是没话说…… 模拟就完了,记录每次的折叠点,每次将之前的都扫一遍就完了 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #define ll long long 8 using namespace std; 9 con

Noip 模拟练习6

Noip 模拟练习6 满分300,本人110.修正后260. 难度中等. 赌徒 Description 有 N 个赌徒,手里各自有自己的筹码.在赌博时,他们能向周围的赌徒借钱,所以他们 的筹码可能是负的,但筹码都一定是整数.当结束赌博时,N 个赌徒当中,筹码刚是另外 3 个 人筹码的总和的赌徒为胜者.如果有多个符合条件的赌徒,选择筹码最大的那个人为胜者. 例如 5 个赌徒,结束赌博时各有 2,3,5,7,12,则他们中的胜者是持有 12 的人,因为 12=2+3+7. Input 第一行为一个整