NOIP模拟47

T1:

  首先思考定义可以发现,类素数实际上降低了素数的条件

可以类比,对于整数系,其由素数唯一组成,那么对于K类素数

其由大于K的素数唯一组成,或者说K类素数不能包含小于等于

K的素数因子

  考场在于筛法的不同,即对于算法理解与具体应用不够,

考场类似试除法筛选,试除法在于单个判断的高效,而对于大数

据筛选,其时间复杂度瓶颈在于范围的枚举,因此大数据效率不

高,对应的倍数法在于范围判断的高效,原理在于范围约数个数

远低于范围数,枚举范围素数可以做到约为nlogn的时间复杂度(

证明采用数列极限)

代码如下:

NOIP模拟47
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I long long
 4 #define C char
 5 #define B bool
 6 const I N = 1e7 + 3;
 7 I l,r,k,ans,cnt,prime[664580];
 8 B not_prime[N],jud[N];
 9 inline I read() {
10     I x(0); C z(getchar());
11     while (!isdigit(z)) z = getchar(); 
12     while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar();
13     return x;
14 }
15 signed main () {
16     l = read(), r = read(), k = read();
17     I tmp = min (k,(I)sqrt(r));
18     for (I i(2);i <= tmp; ++ i) {
19      if (!not_prime[i]) prime[++cnt] = i;
20      for (I j(1);j <= cnt && i * prime[j] <= tmp; ++ j) {
21       not_prime[i * prime[j]] = 1;
22       if (i % prime[j] == 0) break;
23      }
24     }
25     for (I i(1);i <= cnt; ++ i) {
26      I down (max (l,prime[i] << 1)), p1(down / prime[i]), p2(r / prime[i]); 
27      if (down % prime[i]) p1 ++ ;
28      for (I j(p1);j <= p2; ++ j) jud[prime[i] * j - l] = 1;
29     }
30     for (I i(l);i <= r; ++ i) if (!jud[i - l]) ans ^= i;
31     printf ("%lld\n",ans);
32 }
View Code

T2:

  考场在于思路大体正确而实际实现时对于方法的使用不当,

采用贡献的思维,尝试考虑每一种数对答案的贡献,枚举每种数

第一次出现的位置,发现考虑问题子结构的话,每种位置的贡献

还与之后其出现的位置相关,尝试数学无果,于是打了状压。

  正解为考虑当前位置的数(该数最后一次出现的位置),以

其结尾的序列数为dp[x] = (sigma(i,1,k)dp[i]) + 1,正确性显然。

  这两种贡献式的考虑不同点在于DP状态设计(第一次,最后

一次),分析问题考虑为什么第二种更优,发现如果动态看待问题

那么问题等价于每次在序列末尾插入一个数,计算每种数的贡献,

发现问题每次在序列末尾产生变化,如果将DP状态设计为第一次,

那么每次新的数插入将更新之前每种数的贡献,时间复杂度与问题

复杂度不能接受,考虑将DP状态设计为最后一次出现,那么每次更

新只会用之前每种数的贡献对新插入的数作出贡献,表面看是等价

的,然而可以发现第一种DP不符合DP设计中无后效性原则,实际实

现时也会拥有较高难度。

  将DP数组设计出后发现DP转移的形式以向量方式进行,矩阵

乘法优化转移即可(貌似有两种转移方式,一次转移一个元素(常规

方法)与一次转移K个元素,这里给出第二种),转移系数根据补缺

调配即可。(一次转移一个元素在于滚动,即元素转移后必定最大,

于是将其调至末尾,其余向前滚动即可,一次转移K个元素在于K个

元素都是所需的并且转移是内置的)(实际上第一种方式适用范围更

广)。

代码如下:(毒瘤)

NOIP模拟47
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I long long
 4 #define C char
 5 #define V void
 6 #define P pair<I,I>
 7 const I mod = 1e9 + 7;
 8 const I N = 1e6 + 1;
 9 I n,m,t,tmp,sigma,ans,A[N],dp[103],pre[103],M[103][103],SW[103];
10 P Z[103];
11 inline I read() {
12     I x(0); C z(getchar());
13     while (!isdigit(z)) z = getchar(); 
14     while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar();
15     return x;
16 }
17 V Matrix_mul () {
18     I X[103];
19     memset (X,0,sizeof X);
20     for (I k(1);k <= t + 1; ++ k)
21      for (I j(1);j <= t + 1; ++ j)
22       (X[j] += dp[k] * M[k][j]) %= mod;
23     memcpy (dp,X,sizeof X);
24 }
25 V Matrix_self () {
26     I X[103][103];
27     memset (X,0,sizeof X);
28     for (I i(1);i <= t + 1; ++ i)
29      for (I k(1);k <= t + 1; ++ k)
30       for (I j(1);j <= t + 1; ++ j)
31        (X[i][j] += M[i][k] * M[k][j]) %= mod;
32     memcpy (M,X,sizeof X);
33 }
34 V Matrix_qpow (I b) {
35     for (; b ;Matrix_self (), b >>= 1)
36       if (b & 1) Matrix_mul ();
37 }
38 signed main () {
39     n = read(), m = read(), t = read();
40     for (I i(1);i <= t; ++ i) Z[i].second = i;
41     for (I i(1);i <= n; ++ i)
42      Z[A[i] = read()].first = i;
43     sort (Z + 1,Z + t + 1);
44     dp[t + 1] = 1; M[t + 1][t + 1] = 1;
45     for (I i(1);i <= n; ++ i) 
46      tmp = sigma, (sigma += tmp + 1 - dp[A[i]]) %= mod, dp[A[i]] = tmp + 1; 
47     for (I i(1);i <= t; ++ i)
48      for (I j(1);j <= t + 1; ++ j) {
49       M[j][i] = j < i ? pre[j] : pre[j] + 1;
50       (pre[j] += M[j][i]) %= mod; 
51      } 
52     memcpy (SW,dp,sizeof dp);
53     for (I i(1);i <= t; ++ i) dp[i] = SW[Z[i].second];
54     I p(m % t);
55     for (I i(1);i <= p; ++ i) 
56      tmp = sigma, (sigma += tmp + 1 - SW[Z[i].second]) %= mod, dp[i] = tmp + 1;
57     memcpy (SW,dp,sizeof dp);
58     for (I i(1);i <= t; ++ i) 
59      dp[i] = SW[p + i > t ? p + i - t : p + i];
60     Matrix_qpow (m / t);
61     for (I i(1);i <= t; ++ i) ans = (ans + dp[i]) % mod;
62     printf ("%lld\n",(ans + mod) % mod);
63 }
View Code

。。。转移考虑最大化,发现转移量相同,每次选择最小的元素接受

转移量即可(贪心),注意取模改变数学系,不能直接sort,发现元素

大小与其最后一次出现的位置相关,记录并排序即可。

上一篇:剑指 Offer 47. 礼物的最大价值(中等)


下一篇:剑指 Offer 47. 礼物的最大价值