【九校联考-厦门一中NOIP模拟赛】Day1总结

  离NOIP2018越来越近了,然而我仍有一些没有彻底弄懂的地方,有点慌,所以准备从这周开搞搞基础。

  不说别的了,先把这篇总结写完。

 

  Day1的题感觉不是很难,每一道题的暴力也都可写,总的来说难度跟noip差不多吧。

  有一个想吐槽的地方,就是为啥题目把算法都告诉了……

T1 backpack

  期望得分:100

  实际得分:100

  正像题解所说,Day1T1是送分的。不过辛亏我以前做过一道类似的题,要不然只能得60。

  首先40分是送的,完全背包板子。然后发现尽管物品很多,但是体积和价值只有100。所以如果两件物品体积相同,那么就取价值更大的。所以实际上物品最多只有100个。然后一个O(100 * n)就得了60分。

  正解其实我也不知道为啥,不过以前做过一道搜索题,那道题数据范围特别大,但是除了暴力我实在想不出来该咋办,然后看题解时记住了这么一句话:“远距离贪心,近距离暴力”。到了这道题,就变成了“大容量贪心,小容量背包”。于是我们用性价比最高的物品填背包,直到剩余容量在1e5范围内,然后正常完全背包了。

考场代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxm = 1e5 + 5;
21 inline ll read()
22 {
23     ll ans = 0;
24     char ch = getchar(), last = ' ';
25     while(!isdigit(ch)) {last = ch; ch = getchar();}
26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
27     if(last == '-') ans = -ans;
28     return ans;
29 }
30 inline void write(ll x)
31 {
32     if(x < 0) x = -x, putchar('-');
33     if(x >= 10) write(x / 10);
34     putchar(x % 10 + '0');
35 }
36 void MYFILE()
37 {
38 #ifndef mrclr
39     freopen("backpack.in", "r", stdin);
40     freopen("backpack.out", "w", stdout);
41 #endif
42 }
43 
44 int n;
45 ll m;
46 ll dp[maxm];
47 int t[105];
48 
49 void work0()
50 {
51     ll ans = 0;
52     int pos = 1;
53     for(int i = 1; i <= 100; ++i) if((ll)t[i] * (ll)pos > (ll)t[pos] * (ll)i) pos = i;
54     ll x = (m - maxm + (ll)pos - 1) / (ll)pos;
55     m -= x * (ll)pos;
56     ans += x * (ll)t[pos];    
57 //    printf("@%lld\n", ans);
58     for(int i = 1; i <= 100; ++i)
59         for(int j = i; j <= m; ++j)
60             dp[j] = max(dp[j], dp[j - i] + t[i]);
61     write(dp[m] + ans), enter;
62 }
63 
64 int main()
65 {
66     MYFILE();
67     n = read(); m = read();
68     for(int i = 1; i <= n; ++i)
69     {
70         int x = read(), y = read();
71         t[x] = max(t[x], y);
72     }
73     if(m > maxm) {work0(); return 0;}
74     for(int i = 1; i <= 100; ++i)
75         for(int j = i; j <= m; ++j)
76             dp[j] = max(dp[j], dp[j - i] + t[i]);
77 //    for(int j = 1; j <= m; ++j) printf("%lld ", dp[j]); enter;
78     write(dp[m]), enter;
79     return 0;
80 }
81 /*
82 2 15
83 3 2
84 5 3
85 */
View Code

T2 sort

  期望得分:100

  实际得分:100

  讲道理T2看了半天才把题看懂,因为我一直认为si可以等于tj,然后方案数总算不对。换然后看到题面说把{ci}分离成这两个序列,才觉得不对劲。如果对于任何 i和 j,都有si != sj ,那么样例就解释明白了:最大值一定是取sum[mid +1, r] - sum[l, mid];最小值一定是si和ti隔一个取一个。然后有这么个规律:对于当前的一个点x,si已经取到的数量一定大于等于ti取得数量。这个规律不就是括号匹配的方案数吗!答案就是卡特兰数呀。

  然后我就忘了卡特兰数的递推式了。只记得有一个C(n / 2, n),于是现场2n打表前10项,一顿神推竟然推出来了。不过忘了线性求逆元,于是O(nlogn)预处理。辛亏1e6没卡我这个。

  剩下的就是线段树维护区间和,奇偶和了。基本跟普通的线段树一样,不过虽然题目保证区间长度是偶数,但是线段树分治下去的不一定是奇数,所以pushdown的时候还要判断一下是奇数还是偶数累加的值比区间和的一半多1个,多了得补上。

  结果刚开始我没注意这个,以为是建树不对,又重写了一遍,就过更不对了。回头又改这个,这样就耽误了不少时间,导致T3没有多少时间了。

还是考场代码

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("") 
 13 #define space putchar(' ')
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const ll mod = 1e9 + 7;
 21 const int maxn = 1e6 + 5;
 22 inline ll read()
 23 {
 24     ll ans = 0;
 25     char ch = getchar(), last = ' ';
 26     while(!isdigit(ch)) {last = ch; ch = getchar();}
 27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
 28     if(last == '-') ans = -ans;
 29     return ans;
 30 }
 31 inline void write(ll x)
 32 {
 33     if(x < 0) x = -x, putchar('-');
 34     if(x >= 10) write(x / 10);
 35     putchar(x % 10 + '0');
 36 }
 37 void MYFILE()
 38 {
 39 #ifndef mrclr
 40     freopen("sort.in", "r", stdin);
 41     freopen("sort.out", "w", stdout);
 42 #endif
 43 }
 44 
 45 int n, m;
 46 
 47 ll quickpow(ll a, ll b)
 48 {
 49     a %= mod;
 50     ll ret = 1;
 51     while(b)
 52     {
 53         if(b & 1) ret = ret * a % mod;
 54         a  = a * a % mod; b >>= 1;
 55     }
 56     return ret;
 57 }
 58 ll fac[maxn], inv[maxn], cat[maxn];
 59 inline void init(const int& N)
 60 {
 61     fac[1] = 1;
 62     for(int i = 2; i <= N; ++i) fac[i] = fac[i - 1] * i % mod;
 63     inv[N] = quickpow(fac[N], mod - 2);
 64     for(int i = N - 1; i; --i) inv[i] = inv[i + 1] * (i + 1) % mod;
 65     ll x = 1;
 66     for(int i = 2; i <= N; i += 2)
 67     {
 68         x++;
 69         cat[i >> 1] = fac[i] * inv[i >> 1] % mod * inv[i >> 1] % mod * quickpow(x, mod - 2) % mod;
 70     }
 71 }
 72 
 73 int l[maxn << 2], r[maxn << 2];
 74 ll sum[maxn << 2], sum1[maxn << 2], sum0[maxn << 2], lzy[maxn << 2];
 75 void pushup(int now)
 76 {
 77     sum[now] = sum[now << 1] + sum[now << 1 | 1]; sum[now] %= mod;
 78     sum1[now] = sum1[now << 1] + sum1[now << 1 | 1]; sum1[now] %= mod;
 79     sum0[now] = sum0[now << 1] + sum0[now << 1 | 1]; sum0[now] %= mod;
 80 }
 81 void build(int L, int R, int now)
 82 {
 83     l[now] = L; r[now] = R;
 84     if(L == R)
 85     {
 86         sum[now] = read(); sum[now] %= mod;
 87         if(L & 1) sum1[now] = sum[now];
 88         else sum0[now] = sum[now];
 89         return;
 90     }
 91     int mid = (L + R) >> 1;
 92     build(L, mid, now << 1);
 93     build(mid + 1, R, now << 1 | 1);
 94     pushup(now);
 95 }
 96 void pushdown(int now)
 97 {
 98     if(lzy[now])
 99     {
100         ll ha1 = (ll)(r[now << 1] - l[now << 1] + 1) * lzy[now];
101         sum[now << 1] += ha1; sum[now << 1] %= mod;
102         if((r[now << 1] - l[now << 1] + 1) & 1)
103         {
104             if(l[now << 1] & 1) sum1[now << 1] += lzy[now];
105             else sum0[now << 1] += lzy[now];
106         }
107 //        if(l[now << 1] != r[now << 1] || (l[now << 1] == r[now << 1] && (l[now << 1] & 1)))
108             sum1[now << 1] += (ha1 >> 1); sum1[now << 1] %= mod;
109 //        if(l[now << 1] != r[now << 1] || (l[now << 1] == r[now << 1] && !(l[now << 1] & 1)))
110             sum0[now << 1] += (ha1 >> 1); sum0[now << 1] %= mod;
111         ll ha2 = (ll)(r[now << 1 | 1] - l[now << 1 | 1] + 1) * lzy[now];
112         sum[now << 1 | 1] += ha2; sum[now << 1 | 1] %= mod;
113         if((r[now << 1 | 1] - l[now << 1 | 1] + 1) & 1)
114         {
115             if(l[now << 1 | 1] & 1) sum1[now << 1 | 1] += lzy[now];
116             else sum0[now << 1 | 1] += lzy[now];
117         }    
118 //        if(l[now << 1 | 1] != r[now << 1 | 1] || (l[now << 1 | 1] == r[now << 1 | 1] && (l[now << 1 | 1] & 1)))
119             sum1[now << 1 | 1] += (ha2 >> 1); sum1[now << 1 | 1] %= mod;
120 //        if(l[now << 1 | 1] != r[now << 1 | 1] || (l[now << 1 | 1] == r[now << 1 | 1] && !(l[now << 1 | 1] & 1)))
121             sum0[now << 1 | 1] += (ha2 >> 1); sum0[now << 1 | 1] %= mod;
122         lzy[now << 1] += lzy[now]; lzy[now << 1] %= mod;
123         lzy[now << 1 | 1] += lzy[now]; lzy[now << 1] %= mod;
124         lzy[now] = 0;
125     }
126 }
127 void update(int L, int R, int now, int d)
128 {
129     if(L == l[now] && R == r[now])
130     {
131         ll ha = (ll)(R - L + 1) * d;
132         sum[now] += ha; sum[now] %= mod;
133         if((R - L + 1) & 1)
134         {
135             if(L & 1) sum1[now] += d;
136             else sum0[now] += d;
137         }
138         sum1[now] += (ha >> 1); sum1[now] %= mod;
139         sum0[now] += (ha >> 1); sum0[now] %= mod;
140         lzy[now] += d; lzy[now] %= mod;
141         return;
142     }
143     pushdown(now);
144     int mid = (l[now] + r[now]) >> 1;
145     if(R <= mid) update(L, R, now << 1, d);
146     else if(L > mid) update(L, R, now << 1 | 1, d);
147     else update(L, mid, now << 1, d), update(mid + 1, R, now << 1 | 1, d);
148     pushup(now);
149 }
150 ll query(int L, int R, int now, int flg)
151 {
152     if(L == l[now] && R == r[now]) 
153     {
154         if(flg == 0) return sum0[now];
155         else if(flg == 1) return sum1[now];
156         else return sum[now];
157     }
158     pushdown(now);    
159     int mid = (l[now] + r[now]) >> 1;
160     if(R <= mid) return query(L, R, now << 1, flg);
161     else if(L > mid) return query(L, R, now << 1 | 1, flg);
162     else return (query(L, mid, now << 1, flg) + query(mid + 1, R, now << 1 | 1, flg)) % mod;
163 }
164 
165 int main()
166 {
167     MYFILE();
168     n = read(); m = read();
169     init(n << 1);
170     build(1, n << 1, 1);
171     for(int i = 1; i <= m; ++i)
172     {
173         int d = read(), L = read(), R = read();
174         if(d == 0)
175         {
176             int val = read();
177             update(L, R, 1, val);
178         }
179         else
180         {
181             int mid = (L + R) >> 1;
182             write((query(mid + 1, R, 1, 2) - query(L, mid, 1, 2) + mod) % mod), space;
183             ll Min = query(L, R, 1, 0), Max = query(L, R, 1, 1);
184             if(L & 1) swap(Min, Max);
185             write((Max - Min + mod) % mod), space;
186             write(cat[(R - L + 1) >> 1]), enter;
187         }
188     }
189     return 0;
190 }
View Code

T3 digit

  期望得分:0

  实际得分:0

  其实写暴力的时间还是有的,剩了40多分钟。主要原因是题没看懂:数位和到底是什么玩意儿!?样例模拟了半天还是不对,剩20多分钟的时候就放弃了,因为这点时间写生什么都来不及了,还不如检查T1,T2。

  现在发现T3部分分其实特别好拿。数位和就是这个数每一位上的数的和。所以30分暴力只要枚举k进制下L位到R位的所有数即可。

  50分是一个比较水的暴dp。题目数位dp纯粹和唬你的。因为4, 5, 6的最小公倍数是60,所以任何大于60的数只要对60取模就行了。令dp[i][j]表示到第 i 位,数位和 mod 60等于 j 的数的个数。那么就有dp[i][j] = Σdp[i - 1][j - h] (0 <= h < k)。因为j - h可能为负,所以代码应该写成(j - h % 60 + 60) % 60。最后的答案用前缀和的思想:ans = Σdp[R][i] - Σdp[L - 1][i],i 满足能被4,5,6其中一个整除。

  初始化应该是for(i : 0 ~k - 1) dp[1][i % 60]++。刚开始写成了dp[1][i] = 1。只得了20分,debug可好半天。

  满分做法:用矩乘优化。推转移矩阵的时候磨叽了好半天(还是不熟练,没理解透),最后还是看了std的代码。然后跑两遍快速幂。

60分代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const ll mod = 1e9 + 7;
21 const int maxn = 1e3 + 5;
22 inline ll read()
23 {
24     ll ans = 0;
25     char ch = getchar(), last = ' ';
26     while(!isdigit(ch)) {last = ch; ch = getchar();}
27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
28     if(last == '-') ans = -ans;
29     return ans;
30 }
31 inline void write(ll x)
32 {
33     if(x < 0) x = -x, putchar('-');
34     if(x >= 10) write(x / 10);
35     putchar(x % 10 + '0');
36 }
37 void MYFILE()
38 {
39 #ifndef mrclr
40     freopen("digit.in", "r", stdin);
41     freopen("digit.out", "w", stdout);
42 #endif
43 }
44 
45 ll l, r, k;
46 ll dp[maxn][65], ans = 0;
47 
48 int main()
49 {
50     MYFILE();
51     l = read(); r = read(); k = read();
52     if(r > 1000) return 0;
53     for(rg int i = 0; i < k; ++i) dp[1][i % 60]++;
54     for(rg int i = 2; i <= r; ++i)
55         for(rg int j = 0; j < 60; ++j)
56             for(rg int h = 0; h < k; ++h)
57                 dp[i][j] += dp[i - 1][(j - h % 60 + 60) % 60], dp[i][j] %= mod;
58     for(rg int i = 0; i < 60; ++i) 
59         if(!(i % 4) || !(i % 5) || !(i % 6)) ans += dp[r][i] - dp[l - 1][i], ans %= mod;
60     write((ans - (l == 1) + mod) % mod); enter;
61     return 0;
62 }
View Code

100分代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const ll mod = 1e9 + 7;
21 const int N = 60;
22 inline ll read()
23 {
24     ll ans = 0;
25     char ch = getchar(), last = ' ';
26     while(!isdigit(ch)) {last = ch; ch = getchar();}
27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
28     if(last == '-') ans = -ans;
29     return ans;
30 }
31 inline void write(ll x)
32 {
33     if(x < 0) x = -x, putchar('-');
34     if(x >= 10) write(x / 10);
35     putchar(x % 10 + '0');
36 }
37 void MYFILE()
38 {
39 #ifndef mrclr
40     freopen("digit.in", "r", stdin);
41     freopen("digit.out", "w", stdout);
42 #endif
43 }
44 
45 ll l, r, k, ans = 0;
46 
47 struct Mat
48 {
49     ll a[N + 5][N + 5];
50     Mat operator * (const Mat &oth)const
51     {
52         Mat ret; Mem(ret.a, 0);
53         for(int i = 0; i < N; ++i)
54             for(int j = 0; j < N; ++j)
55                 for(int k = 0; k < N; ++k)
56                     ret.a[i][j] = (ret.a[i][j] + a[i][k] * oth.a[k][j]) % mod;
57         return ret;
58     }
59 }f;
60 
61 Mat quickpow(Mat A, ll b)
62 {
63     Mat ret; Mem(ret.a, 0);
64     for(int i = 0; i < 60; ++i) ret.a[i][i] = 1;
65     while(b)
66     {
67         if(b & 1) ret = ret * A;
68         A = A * A; b >>= 1;
69     }
70     return ret;
71 }
72 
73 int main()
74 {
75     MYFILE();
76     ll l = read(), r = read(), k = read();
77     Mem(f.a, 0);
78     for(int i = 0; i < N; ++i)
79     {
80         for(int j = 0; j < N; ++j)
81             f.a[i][j] = k / N % mod;
82         for(int j = 0; j < k % N; ++j)
83             f.a[i][(i + j) % N]++, f.a[i][(i + j) % N] %= mod;
84     }
85     Mat A = quickpow(f, r);
86     for(int i = 0; i < N; ++i)
87         if(!(i % 4) || !(i % 5) || !(i % 6)) ans = (ans + A.a[0][i]) % mod;
88     A = quickpow(f, l - 1);
89     for(int i = 0; i < N; ++i)
90         if(!(i % 4) || !(i % 5) || !(i % 6)) ans = (ans - A.a[0][i] + mod) % mod;
91     write(ans), enter;
92     return 0;
93 }
View Code

  Day1美中不足的地方在于T2花费的时间有点多,而这是因为没有思考周全就开始写代码了,写完后就没有自信,然后有点盲目的改,结果浪费了不少时间。

猜你喜欢

转载自www.cnblogs.com/mrclr/p/9826713.html