• 题解 P5751 【[NOI1999]01串】


    核心算法:差分约束,前缀和

    重点:如何灵活构图来应用差分约束算法。


    准备工作:

    (x_i)为字符串(S)的子串:(s_1...s_i)(1)的个数。

    (前缀和)

    那么(x_i-x_{i-L})所表达的含义即为:(S)的子串:(s_{i-L+1}...s_i)(1)的个数。

    (Lleq i leq n))((L)为子串长度,(n)(S)的长度)

    因为,(S)只由(0,1)组成,所以(l-left(x_i-x_{i-L} ight)) 即为:(S)的子串:(s_{i-L+1}...s_i)(0)的个数。

    差分约束:

    我们将字符串的前缀和(x_i)当作图中的节点,利用差分约束,先求出一组可行解。

    根据题意,我们可以得出:

    (A_1 leq x_i-x_{i-L_1} leq B_1)

    (A_0-L_0 leq x_{i-L_0}-x_i leq B_0-L_0)

    至此,构图还没有结束。

    因为,(S)是一个连续的序列,题目中有一个隐藏的关系:

    (0 leq x_i-x_{i-1} leq 1)

    (同时,因为该关系使图中存在了一个点,使其连通了其余各点,构造超级源点的工作也省去了。)

    细节:

    由于差分约束的多解性,为了使其满足可行解最大。

    不妨设想,(x_1)可行解的最大值是1,所以,我们只要让(x_1=1),那么,整体的值就最大。

    同时,也因为,我们所求的是前缀和,存在单调性。(x_n geq x_1)

    所以得到最后答案为:(x_n-x_1+1)

    (这里我不认为是单单减去(x_0),虽然说,要求(x_0)最大只能是(0),但是不能确保当(x_0=0)时,(x_1=1)。)

    代码如下:

    #include <bits/stdc++.h>
    #define MAXN 500000
    #define INF 0x3f3f3f3f
    using namespace std;
    int adj[MAXN],cnt=0;
    int n,a0,b0,l0,a1,b1,l1;
    struct EDGE { int to,nxt,val; }	e[MAXN];
    void addedge(int u,int v,int w) { e[++cnt].to=v; e[cnt].val=w; e[cnt].nxt=adj[u]; adj[u]=cnt; }
    int dis[MAXN],vis[MAXN],num[MAXN];
    queue < int > q;
    bool SPFA()
    {
    	for(int i=1;i<=n;++i)	{dis[i]=INF;}
    	dis[0]=0; vis[0]=1; ++num[0];	q.push(0);
    	while(!q.empty())
    	{
    		int u=q.front();  q.pop();  vis[u]=0;
    		for(int i=adj[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
                if(dis[v]>dis[u]+e[i].val)
    			{
    				dis[v]=dis[u]+e[i].val;
    				if(!vis[v])
    				{
                        ++num[v];	if(num[v]>=n) return 0;
                        q.push(v); vis[v]=1; 
    				}
    			}
    		}
    	}
    	return 1;
    }
    
    int main()
    {
    	scanf("%d%d%d%d%d%d%d",&n,&a0,&b0,&l0,&a1,&b1,&l1);
    	for(int i=1;i<=n;++i)
    	{
            addedge(i,i-1,0);
            addedge(i-1,i,1);
        }
        for(int i=l0;i<=n;++i)
    	{
            addedge(i,i-l0,b0-l0);
            addedge(i-l0,i,l0-a0);
        }
        for(int i=l1;i<=n;++i)
    	{
            addedge(i,i-l1,-a1);
            addedge(i-l1,i,b1);
        }
        if(SPFA())	printf("%d",dis[n]-dis[1]+1);
        else	printf("-1");
    	return 0;
    }
    
  • 相关阅读:
    [原创]Acronis True Image使用手记
    毕业日志
    我的L6修好了
    三峡实习记之二
    初到华南理工印象
    三峡实习记之三
    SHOW毕业衫
    自己的第一次装机
    iOS Tools
    [转] A few things iOS developers ought to know about the ARM architecture
  • 原文地址:https://www.cnblogs.com/cyl-oi-miracle/p/13762638.html
Copyright © 2020-2023  润新知