多校NOIP24

T1:

  据说是第一类斯特林数,然而考场上并没有看出来,却推出了类似的递推式

  首先想的是数学题,考虑问题形式类似于错位排列,于是考虑的是钦定若干

位置完全匹配,再计算剩余位置错位排列方案即可,然而是假的,因为无法处理

门后钥匙再次进行匹配的问题

  然而这是我找到了问题的子结构,即当门后的钥匙刚好配对时,相当于这次

撞门的机会已经使用完,而当门后钥匙并不配对时,相当于消耗以此撞门机会并

收获一次撞门(开门)机会

  考虑设f[i][j]表示当前有i扇门,还有j次撞门机会的方案数,不妨钦定每次撞门

选定1 号门,那么显然分类讨论有:一号门的钥匙配对/不配对,当不配对时相当

于从剩余i-1扇门中选择一扇门,于是有转移:f[i][j] = f[i - 1][j - 1](消耗一次撞门

机会) + (i - 1) * f[i - 1][j](消耗一次收获一次),发现与第一类斯特林数递推公式

相同

T2:

  与第一题有些类似,考虑设f[i]表示考虑前i个字符的方案数,转移首先直接继

承i - 1状态,考虑第i个字符的贡献,发现因为只能翻转一次,那么当翻转的子串

不回文时一定会做出一次贡献,那么考虑当前字符,可翻转区间为前i - 1个字符,

依次考虑可以发现,当某字符与当前字符相同时,不会造成贡献,因为在前i - 1个

状态的统计中,其一定已经被计算过(因为字符相同,该位置相当于不翻转),于

是开桶统计字符出现次数,递推转移即可

T3:

  明显的图论题,考虑建模的意义,对于一个蛋糕的两种字符,我们将其连边

表示其能相互翻转(转化),那么问题转化为对于一个图,求其最长欧拉路,本

质上就是每条边只能经过一次,求所能经过的最长距离,发现由于只有四个点,

当联通块大小不为4时一定存在一种方案能够遍历所有边,这是显然的,那么并查

集维护联通块权值和即可,当联通块大小为4时,发现对于任意两点之间的若干条

边,我们有两种选择,一是反复横跳遍历所有边,这样根据边数的奇偶会到达两点

中的一点,而假设答案并不在该点,那么我们可以少遍历一条边使得最终到达另一

点,显然贪心的选择不遍历最小的那条边,于是预处理任意两点之间的边数,边权

和以及最小边权,Dfs遍历所有情况即可

代码如下:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define I int
  4 #define C char
  5 #define B bool
  6 #define V void
  7 #define S short
  8 #define D double
  9 #define LL long long
 10 #define LD long double
 11 #define UI unsigned int
 12 #define UL unsigned long long
 13 #define P pair<I,I>
 14 #define MP make_pair
 15 #define a first
 16 #define b second
 17 #define lowbit(x) (x & -x)
 18 #define ot(x) cout << #x << " = " << x << "  ";
 19 #define debug cout << "It's Ok Here !" << endl;
 20 #define FP(x) freopen (#x,"r",stdin)
 21 #define FC(x) freopen (#x,"w",stdout)
 22 #define Tem template<typename T>
 23 // #define memset(name,val,typ,len) memset (name,val,sizeof (typ) * (len))
 24 
 25 inline I read () {
 26     I x (0), y (1); C z (getchar ());
 27     while (!isdigit (z)) { if (z == '-') y = -1; z = getchar (); }
 28     while ( isdigit (z))  x = x * 10 + (z & 15), z = getchar ();
 29     return x * y;
 30 }
 31 Tem inline T abs (T &a) { return a >= 0 ? a : -a; }
 32 Tem inline V Max (T &a,T  b) { a = a > b ? a : b; }
 33 Tem inline V Min (T &a,T  b) { a = a < b ? a : b; }
 34 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; }
 35 #ifdef mod 
 36 Tem inline V Mod1 (T &a,T b) { a = a + b > mod ? a + b - mod : a + b; }
 37 Tem inline V Mod2 (T &a,T b) { a = a - b <  0  ? a - b + mod : a - b; }
 38 Tem inline T Mod3 (T  a,T b) { return a + b > mod ? a + b - mod : a + b; }
 39 Tem inline T Mod4 (T  a,T b) { return a - b <   0 ? a - b + mod : a - b; }
 40 #endif
 41 inline P operator + (const P &a,const P &b) { return MP (a.a + b.a,a.b + b.b); }
 42 inline P operator - (const P &a,const P &b) { return MP (a.a - b.a,a.b - b.b); }
 43 const I N = 5e5 + 3;
 44 I n,ans,tmp1,f[4],s[4],t[4];
 45 I a[4][4],b[4][4],c[4][4];
 46 B jud[4];
 47 I get (I x) {
 48     return x == f[x] ? 
 49         x : f[x] = get (f[x]);
 50 }
 51 V Dfs (I x,I y) {
 52     I tmp2 (c[x][y]), tmp3 (a[x][y]);
 53     switch (a[x][y] & 1) {
 54         case 1 : 
 55             Max (ans,tmp1 += c[x][y]);
 56             c[x][y] = c[y][x] = a[x][y] = a[y][x] = 0;
 57             for (I i(0);i <  4; ++ i) if (a[y][i])
 58                 Dfs (y,i);
 59             a[x][y] = a[y][x] = tmp3, c[x][y] = c[y][x] = tmp2; 
 60             tmp1 -= c[x][y];
 61 
 62             if (a[x][y] != 1 && x != y) {
 63                 tmp1 += c[x][y] - b[x][y], Max (ans,tmp1);
 64                 c[x][y] = c[y][x] = b[x][y], a[x][y] = a[y][x] = 1;
 65                 for (I i(0);i <  4; ++ i) if (a[x][i])
 66                     Dfs (x,i);
 67                 a[x][y] = a[y][x] = tmp3, c[x][y] = c[y][x] = tmp2; 
 68                 tmp1 -= c[x][y] - b[x][y];
 69             }
 70         break;
 71         case 0 : 
 72             Max (ans,tmp1 += c[x][y]);
 73             c[x][y] = c[y][x] = a[x][y] = a[y][x] = 0;
 74             for (I i(0);i <  4; ++ i) if (a[x][i])
 75                 Dfs (x,i);
 76             a[x][y] = a[y][x] = tmp3, c[x][y] = c[y][x] = tmp2; 
 77             tmp1 -= c[x][y];
 78             
 79             if (a[x][y] != 1 && x != y) {
 80                 tmp1 += c[x][y] - b[x][y], Max (ans,tmp1);
 81                 c[x][y] = c[y][x] = b[x][y], a[x][y] = a[y][x] = 1;
 82                 for (I i(0);i <  4; ++ i) if (a[y][i])
 83                     Dfs (y,i);
 84                 a[x][y] = a[y][x] = tmp3, c[x][y] = c[y][x] = tmp2; 
 85                 tmp1 -= c[x][y] - b[x][y];
 86             }
 87         break;
 88     }
 89 }
 90 signed main () {
 91     FP (cake.in), FC (cake.out);
 92     n = read ();
 93     I w,u,d;
 94     memset (b,0x3f,sizeof b);
 95     f[0] = 0, f[1] = 1, f[2] = 2, f[3] = 3;
 96     t[0] = 1, t[1] = 1, t[2] = 1, t[3] = 1;
 97 
 98     for (I i(1);i <= n; ++ i) { w = read ();
 99         u = getchar () - 'W'; getchar (); d = getchar () - 'W';
100         
101         jud[u] = jud[d] = 1; 
102         ++ a[u][d], ++ a[d][u];
103         c[u][d] += w, c[d][u] += w;
104         Min (b[u][d],w), Min (b[d][u],w);
105 
106         I fat1 (get (u)), fat2 (get (d)); s[fat1] += w;
107         if (fat1 == fat2) continue;
108         f[fat2] = fat1, s[fat1] += s[fat2], t[fat1] += t[fat2];
109     }
110     for (I i(0);i <  4; ++ i) if (a[i][i])
111         a[i][i] >>= 1, c[i][i] >>= 1;
112     for (I i(0);i <  4; ++ i) if (f[i] == i && jud[i]) {
113         switch (t[i]) {
114             case 1 : Max (ans,s[i]); break;
115             case 2 : Max (ans,s[i]); break;
116             case 3 : Max (ans,s[i]); break;
117             case 4 : 
118                 for (I i(0);i <  4; ++ i)
119                     for (I j(0);j <  4; ++ j) if (a[i][j])
120                         Dfs (i,j);
121             break;
122         }
123     } 
124     printf ("%d\n",ans);
125 }
View Code

注意邻接矩阵存图要考虑自环的决策

T4:

  二分题,考场并没有做出来,考虑首先时间一定具有单调性,考虑如何Check

不妨将所有坐标排序,那么对于最左侧的x点一定要遍历其左侧所有y点,归纳可以

得到Check的策略,即现将左侧必须选的卷轴拿到,剩余时间再向右走

  注意其可以先向右走一段合法距离再向左拿取所有卷轴

 

posted @ 2021-11-07 17:12  HZOI_LYM  阅读(27)  评论(0编辑  收藏  举报