事实上没有通信题题解。
这两题都没想出完整做法,不知道是不是睡眠质量的问题。按道理来说都应是
“刚好会做” 的题。
按体感难度排序。
loj3690 团队竞技
题意: https://loj.ac/p/3690
老老实实地想了除最后一个包的所有点。
无语住了。
按  从小到大排序,扫描 
最大的那个人,剩下两人都要在他前面。设剩下两人为 ,那么有 。
我们加入一个 
的时候,其实就可以找到与其配对的另一个人 (满足  的  中  最大的,以及满足  的  中  最大的)。
将  与和其配对的点合成一对
,扔到一个二维数据结构里面。扫描到
 时,查询  的  最大值即可。
时间复杂度 。
loj3688 复制粘贴 3
题意 : https://loj.ac/p/3688
想到了区间
DP,但脑子不在状态,只是描绘了一个复制粘贴的形态,没有在纸上细推,导致转移没有编出来。
至于如何想到,其实可以考虑观察样例 
的构造过程。其没有明显的顺序或倒序构造的特征,不过仍然是从小串构造出包含它的大串,即
,这反映到区间上就是
。一条区间 DP 的转移路径。
那么我们可设 
表示不管当前的剪贴板是什么,构造出  的最小步数。
考虑我们剪切了一个串后,用其构造出来的串一定形如  (其中  都是我们手打的字符)。
其中头尾两段不是很好处理,我们考虑编两个转移来包含这两段。
显然有 
(其中  表示 )。
考虑  怎么办 ,我们设  表示构造出 
,且最后一次操作是粘贴的最小步数。
当我们从 
向外转移时,可以先令 ,然后 。
依据  的定义,我们可以转移
。
至此, 和  都处理完了。
那么我们多次粘贴 
时,可以默认我们构造出来的串开头是 ,结尾也是 。
那么我们设  表示  最早的出现位置使得该位置不在  中。
那么我们每次转移暴力跳 
即可转移。
因为我们至多跳 
次,复杂度是  的
( 是调和级数)。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 
 | #include <bits/stdc++.h>using namespace std;
 template<typename T> inline void ckmin(T &x,const T &y) { if(x > y) x = y;}
 const int N = 2.5e3 + 5;
 typedef unsigned long long ull;
 const ull base = 13331;
 int n;
 int A,B,C;
 char s[N];
 int nxt[N][N];
 long long f[N][N],g[N][N];
 ull hsh[N],Pow[N];
 ull h[N][N];
 map<ull,int> ton;
 int main()
 {
 cin >> n;
 cin >> (s + 1);
 cin >> A >> B >> C;
 Pow[0] = 1;
 for(int i = 1;i <= n;i++) Pow[i] = Pow[i - 1] * base;
 for(int i = 1;i <= n;i++) hsh[i] = hsh[i - 1] * base + (s[i] - 'a' + 1);
 for(int i = 1;i <= n;i++)
 for(int j = i;j <= n;j++)
 h[i][j] = hsh[j] - hsh[i - 1] * Pow[j - i + 1];
 for(int l = 1;l <= n;l++)
 {
 ton.clear();
 for(int i = n - l + 1;i + l - 1 > n - l;i--)
 nxt[i][i + l - 1] = n + 1;
 for(int i = n - l - l + 1;i >= 1;i--)
 {
 ton[h[i + l][i + l + l - 1]] = i + l;
 if(ton.find(h[i][i + l - 1]) == ton.end())
 nxt[i][i + l - 1] = n + 1;
 else nxt[i][i + l - 1] = ton[h[i][i + l - 1]];
 }
 }
 memset(f,0x3f,sizeof f);
 memset(g,0x3f,sizeof g);
 for(int i = 1;i <= n;i++)
 f[i][i] = A;
 for(int len = 1;len <= n;len++)
 {
 for(int i = 1;i + len - 1 <= n;i++)
 {
 int j = i + len - 1;
 ckmin(f[i][j],g[i][j]);
 if(j < n) ckmin(f[i][j + 1],f[i][j] + A);
 int now = nxt[i][j],cnt = 2;
 while(now <= n)
 ckmin(f[i][now + len - 1],f[i][j] + B + 1ll * cnt * C + 1ll * A * (now + len - i - cnt * len)),
 ++cnt,now = nxt[now][now + len - 1];
 }
 for(int i = 2;i + len - 1 <= n;i++)
 ckmin(f[i - 1][i + len - 1],f[i][i + len - 1] + A);
 }
 
 cout << f[1][n] << endl;
 return 0;
 }
 
 |