正睿20秋季提高十连测day4

估分:60+20+30=110

实际:60+20+30=110

T1:

  不会,不知道怎么用答案小于50

  先正常的DP,dp[i][j]表示将a的前i个字符转换成b的前j个字符的最小步数,因为答案在五十以内,所以只计算两个字符串长度差为五十以内的状态

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 100010, M = 110;
 8 const int inf = 0x3f3f3f3f;
 9 
10 int n, m;
11 char a[N], b[N];
12 int dp[N][M], ans = inf;
13 
14 int main()
15 {
16     scanf("%s%s", a + 1, b + 1);
17 
18     n = strlen(a + 1);
19     m = strlen(b + 1);
20 
21     memset(dp, 0x3f, sizeof(dp));
22     dp[0][50] = 0;
23     for (int i = 1; i <= m; i++)
24     {
25         for (int k = 0, tmp = dp[i - 1][k]; k <= 100; k++, tmp = std::min(tmp + 1, dp[i - 1][k]))
26         {
27             if (i + k - 50 >= 0 && i + k - 50 <= n)
28             {
29                 dp[i][k] = std::min(dp[i - 1][k + 1] + 1, tmp + (a[i + k - 50] != b[i]));
30             }
31             else
32             {
33                 dp[i][k] = inf;
34             }
35         }
36     }
37                 
38     for (int k = 0; k <= 100; k++)
39     {
40         if (m + k - 50 <= n)
41         {
42             ans = min(ans, dp[m][k] + (n - (m + k - 50)));
43         }
44     }
45             
46     printf("%d", ans > 50 ? -1 : ans);
47 }
View Code

 

T2:

  不会

  用一个大小为200的数组存储2^k的前200位,用一个数组存储k的高精度,可以利用2^(k+l)=2^k*2^l来算。

定义区间[min,max],表示前缀为n个1的值的范围。维护L,R表示当前次幂中前两百位最小的和最大的的前两百位和幂次,初始值为2^1。维护一个数x,初始为1,每次计算x*L,如果x*L前两百位不超过max,则把x乘上L,否则计算L*R,因为L,R,x的初始值都是1,若x*L前两百位大于max时,则计算L*R,所以若L*R的前两百位在[L,R]之间,那在前面一定有x*L小于max,不会运算到这个状态,所以L*R的前两百位不是比L小就是比R大,如果比L小就更新L,比R大就更新R。相当于是不断扩大幂次,L的前两百位是前缀的最小值,R是最大值,在进行x*L和L*R的运算时就在不断增加幂次,所以能算出答案。

  (大概是这样吧,我也不清楚,题解的两个容易发现我是真没发现)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 #define pb push_back
  9 #define mp make_pai
 10 
 11 typedef long long LL;
 12 
 13 const int N = 100010;
 14 const int mxs = 200;
 15 const int mod = 998244353;
 16 
 17 void update(vector<int>& a)
 18 {
 19     for (int i = 0; i < a.size(); i++)
 20     {
 21         if (a[i] >= 10)
 22         {
 23             if (i == a.size() - 1) a.pb(a[i] / 10);
 24             else a[i + 1] += a[i] / 10;
 25             a[i] %= 10;
 26         }
 27     }
 28     if (a.size() > mxs)
 29     {
 30         for (int j = 0; j < mxs; j++) a[j] = a[a.size() - mxs + j];
 31         a.resize(mxs);
 32     }
 33 }
 34 
 35 vector<int> operator * (vector<int>& a, vector<int>& b)
 36 {
 37     vector<int> c(a.size() + b.size() - 1);
 38     for (int i = 0; i < c.size(); i++) c[i] = 0;
 39     for (int i = 0; i < a.size(); i++)
 40     {
 41         for (int j = 0; j < b.size(); j++)
 42         {
 43             c[i + j] += a[i] * b[j];
 44         }
 45     }
 46     update(c);
 47     return c;
 48 }
 49 
 50 bool operator < (vector<int>& a, vector<int>& b)
 51 {
 52     for (int i = a.size() - 1; i >= 0; i--) if (a[i] != b[i]) return a[i] < b[i];
 53     return 0;
 54 }
 55 
 56 vector<int> operator + (vector<int>& a, vector<int>& b)
 57 {
 58     vector<int> c(max(a.size(), b.size()));
 59     for (int i = 0; i < c.size(); i++)
 60     {
 61         c[i] = 0;
 62         if (i < a.size()) c[i] += a[i];
 63         if (i < b.size()) c[i] += b[i];
 64     }
 65     update(c);
 66     return c;
 67 }
 68 
 69 LL qmul(LL a, LL k)
 70 {
 71     LL res = 1;
 72     while (k)
 73     {
 74         if (k & 1) res = res * a % mod;
 75         a = a * a % mod;
 76         k >>= 1;
 77     }
 78     return res;
 79 }
 80 
 81 struct Node
 82 {
 83     vector<int> a;
 84     vector<int> b;
 85     Node() { a.clear(), b.clear(); }
 86     Node(vector<int> a, vector<int> b) :a(a), b(b) {}
 87     Node operator * (Node c)
 88     {
 89         return Node(a * c.a, b + c.b);
 90     }
 91 };
 92 
 93 Node L, R, res;
 94 vector<int> lb, mx; // 满足前缀为n个连续的1的答案范围
 95 char inp[mxs];
 96 
 97 int main() 
 98 {
 99     int n;
100     scanf("%d", &n);
101 
102     vector<int> u, v;
103     for (int i = 0; i < mxs - 1; i++) u.pb(0);
104     u.pb(2), v.pb(1);
105 
106     for (int i = 0; i < mxs - n; i++) lb.pb(0), mx.pb(9);
107     for (int i = n - 1; i >= 0; i--) lb.pb(1), mx.pb(1);
108 
109     L = Node(u, v); // 前两百位 幂次
110     R = Node(u, v);
111 
112     v[0] = 0, u[mxs - 1] = 1;
113     res = Node(u, v);
114 
115     while (true)
116     {
117         while (true)
118         {
119             Node ed = res * L;
120             if (res.a < ed.a && ed.a < mx)
121             {
122                 res = ed;
123                 if (!(res.a < lb))
124                 {
125                     for (int i = res.b.size() - 1; i >= 0; i--) printf("%d", res.b[i]);
126                     return 0;
127                 }
128             }
129             else break;
130         }
131         while (true)
132         {
133             Node num = L * R;
134             if (num.a[mxs - 1] == 1)
135             {
136                 L = num;
137                 break;
138             }
139             else R = num;
140         }
141     }
142 }
View Code

 

T3:

  不会,找到了“忽略已打开的灯后不存在相邻的两盏灯颜色一样”这个规律,但不知道怎么用,没想到逆序枚举

  从小到大枚举颜色,逆序枚举开灯顺序,满足任意时刻合法的情况下使劲染当前枚举到的颜色(忽略已打开的灯后不存在相邻的两盏灯颜色一样)

 1 #include<cstdio>
 2 #include<cstdio>
 3 #include<set>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 const int N = 20010;
 9 
10 int n, m;
11 int tim[N], id[N], v[N];
12 bool vis[N];
13 set<int> s;
14 
15 int main()
16 {
17     scanf("%d%d", &n, &m);
18     for (int i = 1; i <= n; i++) scanf("%d", &tim[i]);
19 
20     int col = 0;
21     while (true)
22     {
23         int len = 0;
24         for (int i = n; i; i--)
25         {
26             if (!id[tim[i]]) v[++len] = tim[i];
27         }
28         if (!len) break;
29         col++;
30         s.insert(0), s.insert(n + 1);
31         for (int i = 1; i <= len; i++)
32         {
33             s.insert(v[i]);
34             vis[v[i]] = false;
35         }
36         for (int i = 1; i <= len; i++)
37         {
38             if (!vis[v[i]])
39             {
40                 id[v[i]] = col;
41                 vis[*--s.lower_bound(v[i])] = true;
42                 vis[*s.upper_bound(v[i])] = true;
43             }
44             s.erase(v[i]);
45         }
46     }
47     for (int i = 1; i <= n; i++) printf("%d ", id[i]);
48 }
View Code

 

总结:

  这次就完全是不会写了,并没有失误。需要注意的就是关于题目的一些数据还是要好好利用。

posted on 2020-09-20 22:12  ArrogHie  阅读(200)  评论(0)    收藏  举报