首页 > 其他分享 >1.19 CW 模拟赛 T2. Everybody Lost Somebody

1.19 CW 模拟赛 T2. Everybody Lost Somebody

时间:2025-01-19 20:13:20浏览次数:1  
标签:Everybody Somebody Lost int height textrm eql sa SA

前言

心态不好, 多想想

那我是不是要去学后缀数组?
好的跑去学了一下()

思路

首先考虑 \(\textrm{sa, height}\) 数组的约束

在此之前先给出一些定义

  • \(\textrm{sa}\) 数组存储排名为 \(i\) 的后缀在原序列上的位置
  • \(\textrm{rank}\) 数组存储原序列上的位置对应的排名
  • \(\textrm{height}\) 数组存储相邻排名的后缀的最大公共前缀

考虑其约束

  • \(\forall i \in (1, n], S[\textrm{sa}_i] \geq S[\textrm{sa}_{i - 1}]\)
    这是显然的, 否则不可能满足排名, 更一般的
    \(\displaystyle rank_{\textrm{sa}_{i-1}+1}>rank_{\textrm{sa}_i+1} \textrm{ s.t. } S[\textrm{sa}_i] > S[\textrm{sa}_{i - 1}] \)

  • \(\forall i \in (1, n], j \in [0, \textrm{height}_i), S[\textrm{sa}_i + j] = S[\textrm{sa}_{i - 1} + j]\)
    也不难理解
    进一步的, 还约束了
    \(\displaystyle i + \textrm{height}_i \leq n \textrm{ s.t. } S[\textrm{sa}_i + \textrm{height}_i] > S[\textrm{sa}_{i - 1} + \textrm{height}_i] \)

好约束全了, 就是说我也是可能想得到

差分约束做法 (\(\rm{fake}\))

思路

看到这一车不等式考虑差分约束

搞得具体一点

首先对于这个约束

\(\forall i \in (1, n], S[\textrm{sa}_i] \geq S[\textrm{sa}_{i - 1}]\)
更一般的
\(\displaystyle rank_{\textrm{sa}_{i-1}+1}>rank_{\textrm{sa}_i+1} \textrm{ s.t. } S[\textrm{sa}_i] > S[\textrm{sa}_{i - 1}] \)

发现可以转化成两种情况

\(S[\textrm{sa}_i] \geq S[\textrm{sa}_{i - 1}] + 0\)
\(S[\textrm{sa}_i] \geq S[\textrm{sa}_{i - 1}] + 1\)

究其原因是 \(S\) 必须是整数, 不然找一个 \(\rm{ASCLL}\) 为 \(16.75\) 的东西给我

其次对于这个约束

\(\forall i \in (1, n], j \in [0, \textrm{height}_i), S[\textrm{sa}_i + j] = S[\textrm{sa}_{i - 1} + j]\)
进一步的
\(\displaystyle i + \textrm{height}_i \leq n \textrm{ s.t. } S[\textrm{sa}_i + \textrm{height}_i] > S[\textrm{sa}_{i - 1} + \textrm{height}_i] \)

类似上面转化成

\(S[\textrm{sa}_i + j] \geq S[\textrm{sa}_{i - 1} + j] + 0\)
\(S[\textrm{sa}_i + j] + 0 \leq S[\textrm{sa}_{i - 1} + j]\)
\(S[\textrm{sa}_i + \textrm{height}_i] \geq S[\textrm{sa}_{i - 1} + \textrm{height}_i] + 1\)

具体为什么要搞成最长路的形式, 在这里进行一次证明
我们想令 \(dis_n \geq dis_1 + L\) , 只有最长路才满足这个柿子, 相当于求出了 \(dis_n\) 的最小值

你发现最长路可能出现正权边, 需要使用 \(\rm{spfa}\)
注意全局加一个 \(S[0] + 1 \leq S[i], i \in [1, n]\)

实现

#include <bits/stdc++.h>
const int MAXN = 5206; //41

int n;
int sa[MAXN], rk[MAXN], height[MAXN]; // 后缀数组常用数组

class graph
{
private:
public:
    struct node { int from, to, w, next; };
    node edge[MAXN * MAXN]; int cnt = 0, head[MAXN];
    /*初始化*/ void head_init() { for (int i = 0; i <= n; i++) head[i] = -1; }
    /*加边*/ void addedge(int u, int v, int w) { edge[++cnt].to = v; edge[cnt].from = u, edge[cnt].w = w, edge[cnt].next = head[u]; head[u] = cnt; }
} gra;

/*建图*/
void mkgra() {
    gra.head_init();

    /*第一类约束*/ for (int i = 2; i <= n; i++) (rk[sa[i - 1] + 1] > rk[sa[i] + 1]) ? gra.addedge(sa[i - 1], sa[i], 1) : gra.addedge(sa[i - 1], sa[i], 0);
    /*第二类约束*/
    for (int i = 2; i <= n; i++) {
        if (!(~height[i])) continue;
        for (int j = 0; j < height[i]; j++) gra.addedge(sa[i] + j, sa[i - 1] + j, 0), gra.addedge(sa[i - 1] + j, sa[i] + j, 0);
        if (i + height[i] <= n) gra.addedge(sa[i - 1] + height[i], sa[i] + height[i], 1);
    }

    /*超级原神*/ for (int i = 1; i <= n; i++) gra.addedge(0, i, 1);
}

int dis[MAXN]; bool inq[MAXN]; std::queue<int> q;
/*差分约束*/
void spfa(int st) {
    memset(inq, false, sizeof inq); memset(dis, 128, sizeof dis);
    dis[st] = 0; q.push(st); inq[st] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop(); inq[u] = false;
        for (int e = gra.head[u]; ~e; e = gra.edge[e].next) {
            int v = gra.edge[e].to, w = gra.edge[e].w;
            if (dis[v] < dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!inq[v]) { inq[v] = true; q.push(v); }
            }
        }
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &sa[i]), rk[sa[i]] = i;
    for (int i = 2; i <= n; i++) scanf("%d", &height[i]);

    mkgra();
    spfa(0);

    for (int i = 1; i <= n; i++) std::cout << char(dis[i] + 'a' - 1);

    return 0;
}

更巧妙的做法

思路

你发现跑差分约束还是太神经了
事实上建出来的图中, \(=0\) 的边连接的两点合并到一起, 剩下的就是个拓扑排序

进一步发现 \(\textrm{sa}\) 一定是一种拓扑排序, 按照其处理即可
\(=0\) 的合并考虑使用并查集

具体一点
首先对于这个约束

\(\forall i \in (1, n], S[\textrm{sa}_i] \geq S[\textrm{sa}_{i - 1}]\)
更一般的
\(\displaystyle rank_{\textrm{sa}_{i-1}+1}>rank_{\textrm{sa}_i+1} \textrm{ s.t. } S[\textrm{sa}_i] > S[\textrm{sa}_{i - 1}] \)

考虑记录所有 \(<\) 的连边, 如果是 \(\leq\) 的连边, 直接在最后计算答案的时候, 把 \(ans_{\textrm{sa}_i}\) 先赋值成 \(S[\textrm{sa}_{i - 1}]\) 即可, 正确性在于 \(\textrm{sa}\) 顺序一定是一个拓扑序

其次对于这个约束

\(\forall i \in (1, n], j \in [0, \textrm{height}_i), S[\textrm{sa}_i + j] = S[\textrm{sa}_{i - 1} + j]\)
也不难理解
进一步的, 还约束了
\(\displaystyle i + \textrm{height}_i \leq n \textrm{ s.t. } S[\textrm{sa}_i + \textrm{height}_i] > S[\textrm{sa}_{i - 1} + \textrm{height}_i] \)

我们考虑把所有 \(=\) 缩成一个点, 然后 \(<\) 正常连边

注意一点是先处理缩点再加边

总的来说, 我们先合并, 再建边, 最后处理答案的时候带上 \(\leq\) 的约束

实现

这个思路不难实现, 直接给出 \(\rm{std}\)

#include <bits/stdc++.h>
#define fo(i, a, b) for (int i = a; i <= b; i++)
using namespace std;

const int maxn = 5005;

int n;
int SA[maxn], Rank[maxn], height[maxn];

int eql[maxn];
vector<int> larger[maxn];
int geteql(int x) { return eql[x] == x ? x : eql[x] = geteql(eql[x]); }

int T;
char ans[maxn];
int main()
{
    scanf("%d", &n);
    fo(i, 1, n) scanf("%d", &SA[i]), Rank[SA[i]] = i;
    fo(i, 2, n) scanf("%d", &height[i]);
    Rank[0] = Rank[n + 1] = 0;

    fo(i, 1, n) eql[i] = i;

    fo(i, 2, n) 
    if (height[i] > -1)
    {
        int x = SA[i - 1], y = SA[i];
        fo(j, 1, height[i]) eql[geteql(x + j - 1)] = geteql(y + j - 1);
    }

    fo(i, 1, n) geteql(i);
    fo(i, 2, n) 
    {
        int x = SA[i - 1], y = SA[i];
        if (~height[i]) {
            if (x + height[i] <= n)
            larger[eql[y + height[i]]].push_back(eql[x + height[i]]);
        }
        
        x = SA[i - 1] + 1, y = SA[i] + 1;
        if (Rank[x] > Rank[y])
            larger[eql[SA[i]]].push_back(eql[SA[i - 1]]);
    }
        

    ans[eql[SA[1]]] = 'a';
    fo(i, 2, n)
    {
        ans[eql[SA[i]]] = ans[eql[SA[i - 1]]]; // 处理 <=
        for (int x : larger[eql[SA[i]]]) // 处理 <
            if (ans[eql[x]] + 1 > ans[eql[SA[i]]])
                ans[eql[SA[i]]] = ans[eql[x]] + 1;
    }

    fo(i, 1, n) putchar(ans[geteql(i)]);
    puts("");
}

看似没改实则改了一堆, 更符合我的理解

总结

约束限制类问题, 考虑具体表示约束
一个误区是递归表示约束, 事实上字典序只需要一个位置更大即可, 不能递归约束

差分约束不够优秀时, 考虑转化成拓扑排序一类问题
注意常见的缩点思想

傳自我的手機:
我們的思想確有問題, 求真的同學們不要用 \(\rm{spfa}\) , 會影響你的數學思維, 三年一篇四大都沒有

标签:Everybody,Somebody,Lost,int,height,textrm,eql,sa,SA
From: https://www.cnblogs.com/YzaCsp/p/18679866

相关文章

  • 视频流媒体播放器EasyPlayer.js出现WebGL: CONTEXT_LOST_WEBGL错误的原因
    选择一个兼容性好、性能稳定的H5视频播放器非常重要。市面上有几款实用的H.265网页播放器,例如EasyPlayer.js播放器,它支持H264和H265视频格式,并且针对低延迟直播进行了优化。那么播放器为什么会显示WebGL:CONTEXT_LOST_WEBGL错误呢?WebGL的CONTEXT_LOST_WEBGL错误通常表示WebGL......
  • H5流媒体播放器EasyPlayer.js播放器关于苹果iOS系统webglcontextlost的问题(ios内核的b
    随着流媒体技术的迅速发展,H5流媒体播放器已成为现代网络视频播放的重要工具。其中,EasyPlayer.js视频流媒体播放器作为一款功能强大的H5播放器,凭借其全面的协议支持、多种解码方式以及跨平台兼容性,赢得了广泛的关注和应用。有时苹果iOS系统会出现webglcontextlost的问题(ios内核的......
  • [USACO03Open] Lost Cows
    题目Description有 NN 头奶牛,已知它们的编号为 1∼N1∼N 且各不相同,但不知道每头奶牛的具体编号。现在这 NN 头奶牛站成一列,已知第 ii 头奶牛前面有 aiai​ 头牛编号小于它,求每头奶牛的编号。Input第 11 行,输入一个整数 NN第 2...N2...N 行,每行输入一个......
  • SQLSTATE[HY000] [2013] Lost connection to MySQL server at 'reading initial commu
    错误信息 SQLSTATE[HY000][2013]LostconnectiontoMySQLserverat'readinginitialcommunicationpacket',systemerror:111 表示在尝试与MySQL服务器建立连接时出现了问题,具体来说是在读取初始通信包时失去了与MySQL服务器的连接,系统错误码为111,这通常表示连接被拒绝......
  • 题解:洛谷 P10497 [USACO03Open] Lost Cows
    原题链接思路+算法首先,考虑读入到\(a_i\)时,如果要得到此时的最优解(指所有牛的编号不重不漏地覆盖\([1,i]\)的所有编号),对于第\(i\)头奶牛,因为在它前面有\(a_i\)头奶牛的编号小于它,所以第\(i\)头奶牛的编号应当为\(a_i+1\)。如果有一头新的奶牛\(i+1\)加入到这个......
  • K11505 The Lost cow[USACO-2017-USOpen-B]
    题目描述FarmerJohn最珍贵的奶牛Bessie丢了,他需要把它找回来。幸运的是,农场里只有一条长长的直路,他知道Bessie肯定在这条路上的某个地方。如果我们把这条路看成数轴,假设FarmerJohn所在位置是x,Bessie所在的位置是y(对于John是未知的),如果FarmerJohn知道Bessie的位置,那么他就......
  • 将 python 脚本的 stdin 重定向到 fifo 会导致 RuntimeError: input():lost sys.stdin
    我有这个python脚本,它的作用是充当服务器,它从重定向到fifo的stdin读取命令:test.py:whileTrue:try:line=input()exceptEOFError:breakprint(f'Received:{line}')在bash中运行命令:mkfifotestfifotest.py<testfifo......
  • 题解:P10733 [NOISG2019 Prelim] Lost Array
    题解:P10733[NOISG2019Prelim]LostArray思路对于任意\(\min(X_{A_{i}},X_{B_{i}})=C_{i}\)。只要让\(X_{A_{i}}\)与\(C_{i}\)取\(\max\)值。\(X_{B_{i}}\)与\(C_{i}\)取\(\max\)值。这样可以让\(\min(X_{A_{i}},X_{B_{i}})\)绝对是\(C_{i}\)。对于为赋值......
  • CodeForces CF1980C Sofia and the Lost Operations 题解 但是最后TLE 仅供思路参考
    CodeForcesCF1980CSofiaandtheLostOperations题解嗨嗨,又来了啊,蒟蒻再来一篇题解SofiaandtheLostOperations题面翻译索菲亚有一个包含$n$个整数的数组$a[1],a[2],…,a[n]$。有一天她对这个数组感到厌倦,于是决定顺序地对其应用$m$个修改操作。每个修改操作由一......
  • LLM troubleshooting for ping lost between containers.
    问题使用dockercompose启动的容器组,容器间不能通信。 LLM问答解决使用docker-compose启动的一组应用,但是容器间网络ping不通,为啥?答当使用docker-compose启动的一组应用出现容器间网络ping不通的情况时,可能的原因和解决方法可以归纳如下:   网络配置错误:       ......