【20180922】noip模拟赛

三道水题……T2差一步就做出来了……

第一题

每次考试都会发现第一题不会做然后去做后面的题之后闲得无聊做了做第一题才发现还是很水的

直接入手的话大概会很棘手,没法做,大胆猜想一下一定是从某个高度往下尽可能的走直到走到地面或者没钱了为止(从下往上走同理,由于这是一个逆操作所以可以合并)

也就是说要证明:不会出现往下走一段再往上走一段

这个十分显然,只需要考虑交换相邻两个高度不一样的楼房之后的代价区别就行了

然后只需要按照高度排序,然后枚举左端点,然后枚举右端点,然后强行选定这两个端点作为起始点和终点,然后对于之间的点按照$c$排序之后从小到大能选就选

于是就做完了……

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 60;
 5 int n; ll T;
 6 struct P { ll c, h; } p[N];
 7 bool operator < (P a, P b) {
 8     if(a.h == b.h) return a.c < b.c;
 9     else return a.h > b.h;
10 }
11 
12 int main() {
13     freopen("meet.in", "r", stdin);
14     freopen("meet.out", "w", stdout); 
15     scanf("%d", &n);
16     for(int i = 1 ; i <= n ; ++ i) scanf("%lld", &p[i].c);
17     for(int i = 1 ; i <= n ; ++ i) scanf("%lld", &p[i].h);
18     sort(p + 1, p + 1 + n);
19     scanf("%lld", &T);
20     int ans = 0;
21     for(int i = 1 ; i <= n ; ++ i)
22         if(p[i].c <= T) {
23             ans = 1;
24             break;
25         }
26     for(int i = 1 ; i <= n ; ++ i) {
27         for(int j = i + 1 ; j <= n ; ++ j) {
28             
29             int lst = j;
30             while(lst - 1 >= i + 1 && p[lst - 1].h == p[j].h) -- lst;
31             swap(p[lst], p[j]);
32         
33             ll t = T - (p[i].h - p[j].h) - p[i].c - p[j].c;
34             
35             if(t >= 0) {
36                 int res = 2;
37                 
38                 // [i + 1, j - 1]
39                 vector<ll> v;
40                 for(int k = i + 1 ; k <= j - 1 ; ++ k) v.push_back(p[k].c);
41                 if(v.size()) {
42                     sort(v.begin(), v.end());
43                     for(int k = 0 ; k < v.size() ; ++ k) {
44                         if(t - v[k] >= 0) {
45                             ++ res;
46                             t -= v[k];
47                         } else break;
48                     }
49                 }
50 //                printf("[%d, %d], res = %d\n", i, j, res);
51                 
52                 ans = max(ans, res);
53             }
54             
55             swap(p[lst], p[j]);
56         }
57     }
58     printf("%d\n", ans);
59 } 
第一题

第二题

第一眼感觉不可做……再想想发现还是很水的……

首先要求的这些数是不降的(因为让你这么输出的)

也就是说按照$a$升序排序之后,前两个数字之和是$a_1$,第一个数字和第三个数字之和是$a_2$,但并不知道$a_3$是谁

这时候只需要知道第二个和第三个数字的和是多少就行了,不妨暴力枚举它们的和

也就是说现在知道了

$$\begin{cases} x_1+x_2=a_1 \\ x_1+x_3=a_2 \\ x_2+x_3=a_t \end{cases}$$

解方程得:$x_1=\frac{a_1+a_2-a_t}{2}$

于是可以剪枝一下:$x_1$是非负整数

如果知道$x_1$,就可以直接依次递推出$x_n$了

  1 // luogu-judger-enable-o2
  2 #pragma GCC optimize(2)
  3 #pragma GCC optimize(3)
  4 #pragma GCC optimize("Ofast")
  5 %:pragma GCC optimize("Ofast")
  6 %:pragma GCC optimize("inline")
  7 %:pragma GCC optimize("-fgcse")
  8 %:pragma GCC optimize("-fgcse-lm")
  9 %:pragma GCC optimize("-fipa-sra")
 10 %:pragma GCC optimize("-ftree-pre")
 11 %:pragma GCC optimize("-ftree-vrp")
 12 %:pragma GCC optimize("-fpeephole2")
 13 %:pragma GCC optimize("-ffast-math")
 14 %:pragma GCC optimize("-fsched-spec")
 15 %:pragma GCC optimize("unroll-loops")
 16 %:pragma GCC optimize("-falign-jumps")
 17 %:pragma GCC optimize("-falign-loops")
 18 %:pragma GCC optimize("-falign-labels")
 19 %:pragma GCC optimize("-fdevirtualize")
 20 %:pragma GCC optimize("-fcaller-saves")
 21 %:pragma GCC optimize("-fcrossjumping")
 22 %:pragma GCC optimize("-fthread-jumps")
 23 %:pragma GCC optimize("-funroll-loops")
 24 %:pragma GCC optimize("-fwhole-program")
 25 %:pragma GCC optimize("-freorder-blocks")
 26 %:pragma GCC optimize("-fschedule-insns")
 27 %:pragma GCC optimize("inline-functions")
 28 %:pragma GCC optimize("-ftree-tail-merge")
 29 %:pragma GCC optimize("-fschedule-insns2")
 30 %:pragma GCC optimize("-fstrict-aliasing")
 31 %:pragma GCC optimize("-fstrict-overflow")
 32 %:pragma GCC optimize("-falign-functions")
 33 %:pragma GCC optimize("-fcse-skip-blocks")
 34 %:pragma GCC optimize("-fcse-follow-jumps")
 35 %:pragma GCC optimize("-fsched-interblock")
 36 %:pragma GCC optimize("-fpartial-inlining")
 37 %:pragma GCC optimize("no-stack-protector")
 38 %:pragma GCC optimize("-freorder-functions")
 39 %:pragma GCC optimize("-findirect-inlining")
 40 %:pragma GCC optimize("-fhoist-adjacent-loads")
 41 %:pragma GCC optimize("-frerun-cse-after-loop")
 42 %:pragma GCC optimize("inline-small-functions")
 43 %:pragma GCC optimize("-finline-small-functions")
 44 %:pragma GCC optimize("-ftree-switch-conversion")
 45 %:pragma GCC optimize("-foptimize-sibling-calls")
 46 %:pragma GCC optimize("-fexpensive-optimizations")
 47 %:pragma GCC optimize("-funsafe-loop-optimizations")
 48 %:pragma GCC optimize("inline-functions-called-once")
 49 %:pragma GCC optimize("-fdelete-null-pointer-checks")
 50 #include <bits/stdc++.h>
 51 #include <unordered_map>
 52 using namespace std;
 53 typedef long long ll;
 54 const int N = 310;
 55 int n; ll a[N * N];
 56 struct FastIO {
 57     static const int S = 1e7;
 58     int wpos;
 59     char wbuf[S];
 60     FastIO() : wpos(0) {}
 61     inline int xchar() {
 62         static char buf[S];
 63         static int len = 0, pos = 0;
 64         if (pos == len)
 65             pos = 0, len = fread(buf, 1, S, stdin);
 66         if (pos == len) exit(0);
 67         return buf[pos++];
 68     }
 69     inline int operator () () {
 70         int c = xchar(), x = 0;
 71         while (c <= 32) c = xchar();
 72         for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
 73         return x;
 74     }
 75     inline ll operator ! () {
 76         int c = xchar(); ll x = 0;
 77         while (c <= 32) c = xchar();
 78         for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
 79         return x;
 80     }
 81     inline void wchar(int x) {
 82         if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
 83         wbuf[wpos++] = x;
 84     }
 85     inline void operator () (ll x) {
 86         if (x < 0) wchar('-'), x = -x;
 87         char s[24];
 88         int n = 0;
 89         while (x || !n) s[n++] = '0' + x % 10, x /= 10;
 90         while (n--) wchar(s[n]);
 91         wchar('\n');
 92     }
 93     inline void space(ll x) {
 94         if (x < 0) wchar('-'), x = -x;
 95         char s[24];
 96         int n = 0;
 97         while (x || !n) s[n++] = '0' + x % 10, x /= 10;
 98         while (n--) wchar(s[n]);
 99         wchar(' ');
100     }
101     inline void nextline() {
102         wchar('\n');
103     }
104     ~FastIO()
105     {
106         if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
107     }
108 } io;
109 
110 ll num[N]; vector<vector<ll> > out; int cnt[N * N]; unordered_map<ll, int> tra;
111 ll ans[310][310]; int T;
112 
113 void get() {
114     int q = 1; cnt[0] = 0;
115     for(int i = 1 ; i <= n * (n - 1) / 2 ; ++ i) cnt[tra[a[i]]] = 0;
116     for(int i = 1 ; i <= n * (n - 1) / 2 ; ++ i) ++ cnt[tra[a[i]]];
117     for(int i = 2 ; i <= n ; ++ i) {
118         while(!cnt[tra[a[q]]]) ++ q;
119         num[i] = a[q] - num[1];
120         for(int j = 1 ; j < i ; ++ j)
121             if(-- cnt[tra[num[j] + num[i]]] < 0)
122                 return ;
123     }
124     ++ T; for(int i = 1 ; i <= n ; ++ i) ans[T][i] = num[i];
125 }
126 
127 int main() {
128     freopen("city.in", "r", stdin);
129     freopen("city.out", "w", stdout); 
130     n = io(); for(int i = 1 ; i <= n * (n - 1) / 2 ; ++ i) a[i] = !io;
131     sort(a + 1, a + 1 + n * (n - 1) / 2);
132     tra[0] = 0; for(int i = 1, tot = 0 ; i <= n * (n - 1) / 2 ; ++ i) tra[a[i]] = ++ tot;
133     
134     unordered_map<ll, int> vis;
135     for(int i = 3 ; i <= n ; ++ i) {
136         num[1] = (a[1] + a[2] - a[i]);
137         if(num[1] <= 0) break;
138         if((num[1] & 1) || vis[num[1] /= 2]) continue;
139         vis[num[1]] = 1, get();
140     }
141     
142     io(T);
143     for(int t = 1 ; t <= T ; ++ t, io.nextline())
144         for(int i = 1 ; i <= n ; ++ i)
145             io.space(ans[T][i]);
146         io.nextline();
147 } 
第二题

第三题

开场先看的这题……数据结构的话应该很可做?(flag)

“模$p$等于$v$”——似曾相识啊,这怕不是洛谷 P3396 哈希冲突

由于数值不超过$10^4$,也就是说对于$p \gt 10^4$实际上是没用的,相当于查询值为$v$的个数,对于每一个数字把出现的下标扔到$vector$中暴力二分就行了

之后就是处理$p \le 10^4$的情况了,考虑按照$sqrt{10^4}$的大小分类讨论

如果$p \le 100$,那么可以预处理一堆$vector$,既$f_{i,j}$表示模$i$等于$j$的下标的集合,其中$1 \le i \le 100$,这样可以$O(10^7)$预处理,然后$O(\log n)$的查询了

如果$p \gt 100$,那么可以暴力去查找$v,v+p,v+2p,v+3p, \dots ,v+kp$,这大约只会执行$100$次

然后就可过了……

当然有更优秀的离线算法……

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 struct FastIO {
 5     static const int S = 1e7;
 6     int wpos;
 7     char wbuf[S];
 8     FastIO() : wpos(0) {}
 9     inline int xchar() {
10         static char buf[S];
11         static int len = 0, pos = 0;
12         if (pos == len)
13             pos = 0, len = fread(buf, 1, S, stdin);
14         if (pos == len) exit(0);
15         return buf[pos++];
16     }
17     inline int operator () () {
18         int c = xchar(), x = 0;
19         while (c <= 32) c = xchar();
20         for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
21         return x;
22     }
23     inline ll operator ! () {
24         int c = xchar(); ll x = 0;
25         while (c <= 32) c = xchar();
26         for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
27         return x;
28     }
29     inline void wchar(int x) {
30         if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
31         wbuf[wpos++] = x;
32     }
33     inline void operator () (ll x) {
34         if (x < 0) wchar('-'), x = -x;
35         char s[24];
36         int n = 0;
37         while (x || !n) s[n++] = '0' + x % 10, x /= 10;
38         while (n--) wchar(s[n]);
39         wchar('\n');
40     }
41     ~FastIO()
42     {
43         if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
44     }
45 } io;
46 
47 const int N = 1e5 + 10;
48 vector<int> pos[N]; int n, m, a[N];
49 vector<int> np[110][110];
50 
51 int calc(vector<int> &v, int n) {
52     if(v.empty() || *v.begin() > n) return 0;
53     return upper_bound(v.begin(), v.end(), n) - v.begin();
54 }
55 
56 int main() {
57     freopen("light.in", "r", stdin);
58     freopen("light.out", "w", stdout); 
59 
60     n = io(), m = io();
61     for(int i = 1 ; i <= n ; ++ i) {
62         a[i] = io();
63         pos[a[i]].push_back(i);
64         for(int j = 1 ; j <= 100 ; ++ j) {
65             np[j][a[i] % j].push_back(i);
66         }
67     }
68     for(int i = 1, l, r, p, v ; i <= m ; ++ i) {
69         l = io(), r = io(), p = io(), v = io();
70         if(p > 10000) {
71             io(calc(pos[v], r) - calc(pos[v], l - 1));
72         } else if(p <= 100) {
73             io(calc(np[p][v], r) - calc(np[p][v], l - 1));
74         } else {
75             int ans = 0;
76             for(int j = v ; j <= 10000 ; j += p)
77                 ans += calc(pos[j], r) - calc(pos[j], l - 1);
78             io(ans);
79         }
80     }
81 } 
第三题

转载于:https://www.cnblogs.com/KingSann/articles/9690329.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值