NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索



  直接暴力模拟,注意判数据结构为空时的取出操作。

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<ctime>
 4 #include<cctype>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<fstream>
 8 #include<sstream>
 9 #include<algorithm>
10 #include<map>
11 #include<set>
12 #include<stack>
13 #include<queue>
14 #include<vector>
15 #include<stack>
16 using namespace std;
17 typedef bool boolean;
18 const signed int inf = (signed)((1u << 31) - 1);
19 #define smin(a, b) a = min(a, b)
20 #define smax(a, b) a = max(a, b)
21 #define max3(a, b, c) max(a, max(b, c))
22 #define min3(a, b, c) min(a, min(b, c))
23 template<typename T>
24 inline boolean readInteger(T& u){
25     char x;
26     int aFlag = 1;
27     while(!isdigit((x = getchar())) && x != ‘-‘ && x != -1);
28     if(x == -1) {
29         ungetc(x, stdin);
30         return false;
31     }
32     if(x == ‘-‘){
33         x = getchar();
34         aFlag = -1;
35     }
36     for(u = x - ‘0‘; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - ‘0‘);
37     ungetc(x, stdin);
38     u *= aFlag;
39     return true;
40 }
41
42 int n;
43 stack<int> s;
44 queue<int> q;
45 priority_queue<int> que;
46 boolean prob[3] = {true, true, true};
47
48 inline void solve() {
49     int opt, a, x;
50     readInteger(n);
51     while(n--) {
52         readInteger(opt);
53         readInteger(a);
54         if(opt == 1) {
55             if(prob[0])    s.push(a);
56             if(prob[1]) q.push(a);
57             if(prob[2])    que.push(a);
58         } else {
59             if(prob[0]) {
60                 if(s.empty()) prob[0] = false;
61                 else {
62                     x = s.top();s.pop();
63                     if(x != a)    prob[0] = false;
64                 }
65             }
66             if(prob[1]) {
67                 if(q.empty()) prob[1] = false;
68                 else {
69                     x = q.front();q.pop();
70                     if(x != a)    prob[1] = false;
71                 }
72             }
73             if(prob[2]) {
74                 if(que.empty()) prob[2] = false;
75                 else {
76                     x = que.top();que.pop();
77                     if(x != a)    prob[2] = false;
78                 }
79             }
80         }
81     }
82     puts(prob[0] ? "YES" : "No");
83     puts(prob[1] ? "YES" : "No");
84     puts(prob[2] ? "YES" : "No");
85 }
86
87 int main() {
88     freopen("qu.in", "r", stdin);
89     freopen("qu.out", "w", stdout);
90     solve();
91     return 0;
92 }




  考虑只有两个任务的时候,只有两种情况,它们的答案分别是。又因为,所以有,所以它们的谁更优取决于。即d值的大小。

  现在考虑多个任务的时候,先随便安排一种执行任务的顺序,如果存在有关d值的逆序对,那么说明当前这个顺序一定不优,我们可以通过交换相邻的一对逆序对使得结果更优。最优时即不存在有关d的逆序对吗,即按d值排序再计算答案就好了。

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<ctime>
 4 #include<cctype>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<fstream>
 8 #include<sstream>
 9 #include<algorithm>
10 #include<map>
11 #include<set>
12 #include<stack>
13 #include<queue>
14 #include<vector>
15 #include<stack>
16 using namespace std;
17 typedef bool boolean;
18 const signed int inf = (signed)((1u << 31) - 1);
19 #define smin(a, b) a = min(a, b)
20 #define smax(a, b) a = max(a, b)
21 #define max3(a, b, c) max(a, max(b, c))
22 #define min3(a, b, c) min(a, min(b, c))
23 template<typename T>
24 inline boolean readInteger(T& u){
25     char x;
26     int aFlag = 1;
27     while(!isdigit((x = getchar())) && x != ‘-‘ && x != -1);
28     if(x == -1) {
29         ungetc(x, stdin);
30         return false;
31     }
32     if(x == ‘-‘){
33         x = getchar();
34         aFlag = -1;
35     }
36     for(u = x - ‘0‘; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - ‘0‘);
37     ungetc(x, stdin);
38     u *= aFlag;
39     return true;
40 }
41
42 typedef class Task {
43     public:
44         int t;
45         int d;
46
47         Task(int t = 0, int d = 0):t(t), d(d) {        }
48
49         boolean operator < (Task b) const {
50             if(d != b.d)    return d < b.d;
51             return t < b.t;
52         }
53 }Task;
54
55 int n;
56 Task* ts;
57
58 inline void init() {
59     readInteger(n);
60     ts = new Task[(const int)(n + 1)];
61     for(int i = 1; i <= n; i++) {
62         readInteger(ts[i].t);
63         readInteger(ts[i].d);
64     }
65 }
66
67 int res = 0;
68 inline void solve() {
69     sort(ts + 1, ts + n + 1);
70     int fin = 0;
71     for(int i = 1; i <= n; i++) {
72         fin += ts[i].t;
73         smax(res, max(0, fin - ts[i].d));
74     }
75     printf("%d\n", res);
76 }
77
78 int main() {
79     freopen("ming.in", "r", stdin);
80     freopen("ming.out", "w", stdout);
81     init();
82     solve();
83     return 0;
84 }




  先说一下70分做法(由于数据比较水,所以暴力基本上可以过7个点)吧。

  1. 暴力建图,然后用树归去统计。每到一个点,先统计它所在的子树的大小。然后用当前子树大小乘它和这个新树的大小再乘它到父节点的那条边的权(乘法原理)。累加起来就是答案。
  2. 这种做法不用建图,首先可以直接求的几个量:连接两棵树的边对答案的贡献,两边的树内部的路径对答案的贡献。现在我们希望求得经过这条边的路径对答案的贡献。根据人生的哲理和组合计数上的经验,我们可以轻松得到这个长度等于左边所有到左边连接点的路径距离总和乘右边节点数,对于右边同理。现在想要快速在O(n)的时间内处理掉这个路径长度总和又不建树,就可以按边一直分下去(类似于边分治吧)。
    我先画一幅图:

    显然在子树b内,可以求出其中的点到点d的距离和,在子树a内也可以用一样的方法求出其中的点到点p的距离,随后是不是还差了点什么?好像子树b内的路径没有延伸到点p。因为树上的路径是唯一的,我们只需要补上路径d-c-p的长度乘子树b内节点数就可以求答案。

  我在考试的时候用的是方法1。

Code

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<ctime>
  4 #include<cctype>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<fstream>
  8 #include<sstream>
  9 #include<algorithm>
 10 #include<map>
 11 #include<set>
 12 #include<stack>
 13 #include<queue>
 14 #include<vector>
 15 #include<stack>
 16 using namespace std;
 17 typedef bool boolean;
 18 const signed int inf = (signed)((1u << 31) - 1);
 19 #define smin(a, b) a = min(a, b)
 20 #define smax(a, b) a = max(a, b)
 21 #define max3(a, b, c) max(a, max(b, c))
 22 #define min3(a, b, c) min(a, min(b, c))
 23 template<typename T>
 24 inline boolean readInteger(T& u){
 25     char x;
 26     int aFlag = 1;
 27     while(!isdigit((x = getchar())) && x != ‘-‘ && x != -1);
 28     if(x == -1) {
 29         ungetc(x, stdin);
 30         return false;
 31     }
 32     if(x == ‘-‘){
 33         x = getchar();
 34         aFlag = -1;
 35     }
 36     for(u = x - ‘0‘; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - ‘0‘);
 37     ungetc(x, stdin);
 38     u *= aFlag;
 39     return true;
 40 }
 41
 42 ///map template starts
 43 typedef class Edge{
 44     public:
 45         int end;
 46         int next;
 47         int w;
 48         Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w){}
 49 }Edge;
 50
 51 typedef class MapManager{
 52     public:
 53         int ce;
 54         int *h;
 55         Edge *edge;
 56         MapManager(){}
 57         MapManager(int points, int limit):ce(0){
 58             h = new int[(const int)(points + 1)];
 59             edge = new Edge[(const int)(limit + 1)];
 60             memset(h, 0, sizeof(int) * (points + 1));
 61         }
 62         inline void addEdge(int from, int end, int w){
 63             edge[++ce] = Edge(end, h[from], w);
 64             h[from] = ce;
 65         }
 66         inline void addDoubleEdge(int from, int end, int w){
 67             addEdge(from, end, w);
 68             addEdge(end, from, w);
 69         }
 70         Edge& operator [] (int pos) {
 71             return edge[pos];
 72         }
 73 }MapManager;
 74 #define m_begin(g, i) (g).h[(i)]
 75 ///map template ends
 76
 77 const int moder = 1e9 + 7;
 78
 79 int n;
 80 MapManager *g;
 81 int* siz;
 82 int s[100005];        // The size of node i.
 83 int fs[100005];        // The length of a edge which connects node i and its father node.
 84
 85 inline int mod_plus(int a, int b) {
 86     int ret = a + b;
 87     while(ret >= moder)    ret -= moder;
 88     return ret;
 89 }
 90
 91 inline void init() {
 92     readInteger(n);
 93     g = new MapManager[(const int)(n + 1)];
 94     siz = new int[(const int)(n + 1)];
 95     siz[0] = 1;
 96     g[0] = MapManager(1, 0);
 97 }
 98
 99 int cnt = 0;
100 inline void mknewtree(int a, int b, int c, int d, int l) {    // Make a new tree following the recipe within O(n).
101     cnt++;
102     siz[cnt] = siz[a] + siz[b];
103     g[cnt] = MapManager(siz[cnt], siz[cnt] << 1);
104     for(int i = 0; i < siz[a]; i++)
105         for(int j = m_begin(g[a], i); j; j = g[a][j].next)
106             g[cnt].addEdge(i, g[a][j].end, g[a][j].w);
107     for(int i = 0; i < siz[b]; i++)
108         for(int j = m_begin(g[b], i); j; j = g[b][j].next)
109             g[cnt].addEdge(i + siz[a], g[b][j].end + siz[a], g[b][j].w);
110     g[cnt].addDoubleEdge(c, d + siz[a], l);
111 }
112
113 int res = 0;
114 void calcLength(int node, int fa) {
115     s[node] = 1;
116     for(int i = m_begin(g[cnt], node); i; i = g[cnt][i].next) {
117         int& e = g[cnt][i].end;
118         if(e == fa)    continue;
119         fs[e] = g[cnt][i].w;
120         calcLength(e, node);
121         s[node] += s[e];
122     }
123     res = mod_plus(res ,(s[node] * 1LL * (siz[cnt] - s[node]) * fs[node]) % moder);
124 }
125
126 inline void solve() {
127     int a, b, c, d, l;
128     while(n--) {
129         readInteger(a);
130         readInteger(b);
131         readInteger(c);
132         readInteger(d);
133         readInteger(l);
134         mknewtree(a, b, c, d, l);
135         res = 0, fs[0] = 0;
136         calcLength(0, -1);
137         printf("%d\n", res);
138     }
139 }
140
141 int main() {
142     freopen("zi.in", "r", stdin);
143     freopen("zi.out", "w", stdout);
144     init();
145     solve();
146     return 0;
147 }

70分做法

  方法1似乎无法优化了,但是方法2很有搞头,因为不用建树。你可以试试人工模拟几组数据,然后你会惊讶地发现真正的状态数并不多,大概也就O(m2)吧,对于树上任意两点的距离,也就顶多连接点的组合,而这些点的(不同树上的总共)个数都是O(m)的。而考虑树上一棵树到其任意一点的距离总和,也就是到的都是连接点,数量也不多。因此2个map强势登场一堆记忆化加上直接把这道题水掉了。。

  如果还不清楚就结合代码看吧。

Code

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<ctime>
  4 #include<cctype>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<fstream>
  8 #include<sstream>
  9 #include<algorithm>
 10 #include<map>
 11 #include<set>
 12 #include<stack>
 13 #include<queue>
 14 #include<vector>
 15 #include<stack>
 16 #ifndef WIN32
 17 #define Auto "%lld"
 18 #else
 19 #define Auto "%I64d"
 20 #endif
 21 using namespace std;
 22 typedef bool boolean;
 23 const signed int inf = (signed)((1u << 31) - 1);
 24 #define smin(a, b) a = min(a, b)
 25 #define smax(a, b) a = max(a, b)
 26 #define max3(a, b, c) max(a, max(b, c))
 27 #define min3(a, b, c) min(a, min(b, c))
 28 template<typename T>
 29 inline boolean readInteger(T& u){
 30     char x;
 31     int aFlag = 1;
 32     while(!isdigit((x = getchar())) && x != ‘-‘ && x != -1);
 33     if(x == -1) {
 34         ungetc(x, stdin);
 35         return false;
 36     }
 37     if(x == ‘-‘){
 38         x = getchar();
 39         aFlag = -1;
 40     }
 41     for(u = x - ‘0‘; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - ‘0‘);
 42     ungetc(x, stdin);
 43     u *= aFlag;
 44     return true;
 45 }
 46
 47 #define LL long long
 48
 49 template<typename T1, typename T2>
 50 inline pair<T1, T2> mkpair(T1 a, T2 b) {
 51     return pair<T1, T2>(a, b);
 52 }
 53
 54 const LL moder = 1e9 + 7;
 55
 56 LL n;
 57 LL *a, *b, *l;
 58 LL *c, *d;
 59 LL* siz;
 60 LL* res;
 61
 62 inline LL mod_plus(LL a, LL b) {
 63     LL ret = a + b;
 64 //    while(ret >= moder)    ret -= moder;
 65     return ret % moder;
 66 }
 67
 68 inline void init() {
 69     readInteger(n);
 70     siz = new LL[(const LL)(n + 1)];
 71     siz[0] = 1;
 72     a = new LL[(const LL)(n + 1)];
 73     b = new LL[(const LL)(n + 1)];
 74     c = new LL[(const LL)(n + 1)];
 75     d = new LL[(const LL)(n + 1)];
 76     l = new LL[(const LL)(n + 1)];
 77     res = new LL[(const LL)(n + 1)];
 78     for(LL i = 1; i <= n; i++) {
 79         readInteger(a[i]);
 80         readInteger(b[i]);
 81         readInteger(c[i]);
 82         readInteger(d[i]);
 83         readInteger(l[i]);
 84         siz[i] = siz[a[i]] + siz[b[i]];
 85     }
 86 }
 87
 88 map<pair<LL, pair<LL, LL> >, LL> dis;        // Records the distance between node u and node v in tree tr.
 89 map<pair<LL, LL>, LL> D;                        // Records
 90
 91 LL length(LL tr, LL u, LL v) {    // Calculate the distance from node u to node v
 92     if(tr == 0)    return 0;
 93     pair<LL, pair<LL, LL> > key = mkpair(tr, mkpair(u, v));
 94     if(dis.count(key))    return dis[key];
 95     LL ls = siz[a[tr]];
 96     LL ret;
 97     if(u < ls && v < ls)    ret = length(a[tr], u, v);
 98     else if(u >= ls && v >= ls)    ret = length(b[tr], u - ls, v - ls);
 99     else {
100         if(u > v)    swap(u, v);
101         ret = mod_plus(mod_plus(length(a[tr], u, c[tr]), l[tr]), length(b[tr], v - ls, d[tr]));
102     }
103     return dis[key] = ret;
104 }
105
106 LL calc(LL tr, LL p) {    // Calculate the distance from all the nodes in tree tr to node p in tree tr
107     if(tr == 0)    return 0;
108     pair<LL, LL> key = mkpair(tr, p);
109     if(D.count(key))    return D[key];
110     LL ls = siz[a[tr]];
111     LL ret;
112     if(p < ls) {            // Node p is in tree a[tr].
113         ret = (length(tr, d[tr] + ls, p) * 1LL * siz[b[tr]]) % moder;
114         ret = mod_plus(ret, calc(a[tr], p));
115         ret = mod_plus(ret, calc(b[tr], d[tr]));
116     } else {                // Otherwise node p is in tree b[tr].
117         ret = (length(tr, c[tr], p) * 1LL * siz[a[tr]]) % moder;
118         ret = mod_plus(ret, calc(a[tr], c[tr]));
119         ret = mod_plus(ret, calc(b[tr], p - ls));
120     }
121     return D[key] = ret;
122 }
123
124 inline void solve() {
125     res[0] = 0;
126     for(LL i = 1; i <= n; i++) {
127         res[i] = mod_plus(((siz[a[i]] % moder) * 1LL * (siz[b[i]] % moder) % moder * 1LL * l[i]) % moder, mod_plus(res[a[i]], res[b[i]]));
128         LL x = calc(a[i], c[i]);
129         LL y = calc(b[i], d[i]);
130         res[i] = mod_plus(mod_plus(res[i], (x * siz[b[i]]) % moder), (y * siz[a[i]]));
131     }
132     for(LL i = 1; i <= n; i++)
133         printf(Auto"\n", res[i]);
134 }
135
136 int main() {
137     freopen("zi.in", "r", stdin);
138     freopen("zi.out", "w", stdout);
139     init();
140     solve();
141     return 0;
142 }
时间: 2024-10-17 21:00:35

NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索的相关文章

Codeforces Round #536 E. Lunar New Year and Red Envelopes /// 贪心 记忆化搜索 multiset取最大项

题目大意: 给定n m k:(1≤n≤1e5, 0≤m≤200, 1≤k≤1e5) 表示n个时间长度内 最多被打扰m次 k个红包 接下来k行描述红包 s t d w:(1≤s≤t≤d≤n , 1≤w≤1e9) 表示在 s 到 t 的时间内都可开始获得该红包 该红包在时间 d 时才能完成获得 红包内有w硬币 在同一时间段内只能获得一个红包 不能同时获得两个及以上 求在被打扰的情况下使获得的红包硬币最少 是多少 用in out标记各红包可被获得的区间 用multiset维护在某个时间点可获得的红包有

[CSP-S模拟测试]:彩球问题(记忆化搜索)

题目传送门(内部题91) 输入格式 第一行一个正整数$N$,表示颜色种类数. 第二行$N$个正整数$k[i],k[i]$表示第$i$种颜色的数量$(1\leqslant k[i]\leqslant 3)$. 输出格式 一个整数,表示相同颜色的小球不相邻的方案数. 样例 样例输入1: 31 2 3 样例输出1: 10 样例输入2: 41 3 2 1 样例输出2: 96 数据范围与提示 输入的所有数字均为正整数. 题解 正解(组合数学$+$容斥原理$+$高精度计算$+$动态规划)好麻烦,我不会……

HDU 1142 A Walk Through the Forest (Dijkstra + 记忆化搜索 好题)

A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6350    Accepted Submission(s): 2332 Problem Description Jimmy experiences a lot of stress at work these days, especial

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&amp;&amp;NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇 今天早上起床发现194了然后就各种刷--当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题--结果尼玛调了能有一个小时--我居然没看到编号最小这个限制0.0 首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减 于是我们记忆化搜索 首先用

TSP+期望——lightoj1287记忆化搜索,好题!

感觉是很经典的题 记忆化时因为不好直接通过E判断某个状态是否已经求过,所以再加一个vis打标记即可 /*E[S][u]表示从u出发当前状态是S的期望*/ #include<bits/stdc++.h> using namespace std; #define N 16 #define INF 0x3f3f3f3f int mp[N][N],n,m; double E[N][1<<N]; bool vis[N][1<<N]; bool dfs(int S,int root

【noip模拟题】挖掘机(模拟题+精度)

这题直接模拟. 可是我挂在了最后两个点上QAQ.唯一注意的是注意精度啊...用来double后边转成整数就忘记用longlong...sad #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> #include <

刷题总结——选课(ssoj树形dp+记忆化搜索+多叉树转二叉树)

题目: 题目描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了 N(N<300)门的选修课程,每个学生可选课程的数量 M 是给定的.学生选修了这M门课并考核通过就能获得相应的学分.在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如<Frontpage>必须在选修了<Windows操作基础>之后才能选修.我们称<Windows操作基础>是<Frontpage

BZOJ 3208 花神的秒题计划Ⅰ 记忆化搜索

题目大意:给定一个矩阵,多次改变某个点的权值,设定某个子矩阵内的所有点可用/禁用,求滑雪的最大长度 再也不敢不看数据范围就做题了233333 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 710 using namespace std; const int dx[]={0,0,1,-1}; const int dy[]={1,-1

[2017浙工大之江学院决赛 M] qwb与二叉树(记忆化搜索,卡特兰数)

题目链接:http://115.231.222.240:8081/JudgeOnline/problem.php?cid=1005&pid=12 题意:中文题面. 假如不限定叶子数的话,问题就是求二叉树形态数,可以每次枚举节点数,以后来的节点为根,左右子树的形态数做乘法原理得到,就是卡特兰数. 这里多限定了叶子数,其实没有什么区别,在枚举的时候,左右子树再分别统计一下不同叶子数的情况就行. 1 #include <bits/stdc++.h> 2 using namespace std