Wannafly挑战赛9 E 组一组


迪杰斯特拉:

对n个数的每一位分别用差分约束建图,用sum[i]表示前i项的前缀和,
则可以得出几组关系。建图后跑出的d[i]就是sum的一组可行解。
剪枝:如果op=2;则L,R之间的数有的位数就要求都是1。因此可以
建立sum[i]-sum[0]的边来剪枝。

代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int op[maxn],L[maxn],R[maxn],x[maxn],n,m;
int sum[maxn],tol,head[maxn],d[maxn],ans[maxn];
bool vis[maxn];
stack<int>P;
struct node
{
    int to,cost,next;
}rode[10*maxn];
void init()
{
    tol=0;
    memset(sum,0,sizeof(sum));
    memset(head,-1,sizeof(head));
}
void add(int a,int b,int c)
{
    rode[tol].to=b;
    rode[tol].cost=c;
    rode[tol].next=head[a];
    head[a]=tol++;
}
void spfa()
{
    for(int i=0;i<=maxn;i++)
        d[i]=-INF;
    memset(vis,0,sizeof(vis));
    P.push(0);vis[0]=1;d[0]=0;
    while(!P.empty())
    {
        int v=P.top();P.pop();vis[v]=0;
        for(int i=head[v];i!=-1;i=rode[i].next)
        {
            node e=rode[i];
            if(d[e.to]<d[v]+e.cost)
            {
                d[e.to]=d[v]+e.cost;
                if(!vis[e.to])
                {
                    P.push(e.to);
                    vis[e.to]=1;
                }
            }
        }
    }
}
int main()
{
    memset(ans,0,sizeof(ans));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d%d",&op[i],&L[i],&R[i],&x[i]);
    for(int t=0;t<20;t++)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            //0<=sum[i]-sum[i-1]<=1;
            //sum[i]-sum[i-1]>=0;
            add(i-1,i,0);
            //sum[i-1]-sum[i]>=-1;
            add(i,i-1,-1);
        }
        for(int i=1;i<=m;i++)
        {
            int a=L[i],b=R[i];
            if(op[i]==1)
            {
                if(x[i]&(1<<t))
                {
                    //sum[b]-sum[a-1]>=1;
                    add(a-1,b,1);
                }
                else
                {
                    //0<=sum[b]-sum[a-1]<=0;
                    add(a-1,b,0);
                    add(b,a-1,0);
                }
            }
            else
            {
                if(x[i]&(1<<t))
                {
                    //b-a+1<=sum[b]-sum[a-1]<=b-a+1;
                    //sum[b]-sum[a-1]>=b-a+1;
                    //sum[a-1]-sum[b]>=a-b-1;
                    add(a-1,b,b-a+1);
                    add(b,a-1,a-b-1);
                    sum[a]++;sum[b+1]--;
                }
                else
                {
                    //0<=sum[b]-sum[a-1]<=b-a;
                    //sum[b]-sum[a-1]>=0;
                    //sum[a-1]-sum[b]>=a-b;
                    add(a-1,b,0);
                    add(b,a-1,a-b);
                }
            }
        }
        for(int i=1;i<=n;i++)
            sum[i]+=sum[i-1];
        for(int i=1;i<=n;i++)
            if(sum[i])sum[i]=1;
        for(int i=1;i<=n;i++)
            sum[i]+=sum[i-1];
        for(int i=1;i<=n;i++)
        {
            //sum[i]-sum[0]
            add(0,i,sum[i]);
        }
        spfa();
        //for(int i=1;i<=n;i++)
            //d[i]=-d[i];
        for(int i=1;i<=n;i++)
        {
            ans[i]=ans[i]+(d[i]-d[i-1])*(1<<t);
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d%c",ans[i],i==n?'\n':' ');
    return 0;
}
spfa:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int op[maxn],L[maxn],R[maxn],x[maxn],n,m;
int sum[maxn],d[maxn],ans[maxn];
bool vis[maxn];
struct node
{
    int to,cost;
};
vector<node>rode[maxn];
void add(int a,int b,int c)
{
    node r;r.to=b;r.cost=c;
    rode[a].push_back(r);
}
struct node2
{
    int id,len;
};
bool operator<(node2 a,node2 b)
{
    return a.len<b.len;
}
priority_queue<node2>P;
void Dij()
{
    for(int i=0;i<maxn;i++)
        d[i]=-INF;
    //memset(vis,0,sizeof(vis));
    node2 r;r.id=0;r.len=0;
    P.push(r);d[0]=0;
    while(!P.empty())
    {
        int v=P.top().id;
        int Len=P.top().len;
        P.pop();
        //vis[v]=1;
        if(d[v]>Len)continue;
        int L=rode[v].size();
        for(int i=0;i<L;i++)
        {
            node e=rode[v][i];
            if(d[e.to]<d[v]+e.cost)
            {
                d[e.to]=d[v]+e.cost;
                r.id=e.to;r.len=d[e.to];
                P.push(r);
            }
        }
    }
}
void init()
{
    memset(sum,0,sizeof(sum));
    for(int i=0;i<maxn;i++)
        rode[i].clear();
}
int main()
{
    memset(ans,0,sizeof(ans));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d%d",&op[i],&L[i],&R[i],&x[i]);
    for(int t=0;t<20;t++)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            //0<=sum[i]-sum[i-1]<=1;
            //sum[i]-sum[i-1]>=0;
            add(i-1,i,0);
            //sum[i-1]-sum[i]>=-1;
            add(i,i-1,-1);
        }
        for(int i=1;i<=m;i++)
        {
            int a=L[i],b=R[i];
            if(op[i]==1)
            {
                if(x[i]&(1<<t))
                {
                    //sum[b]-sum[a-1]>=1;
                    add(a-1,b,1);
                }
                else
                {
                    //0<=sum[b]-sum[a-1]<=0;
                    add(a-1,b,0);
                    add(b,a-1,0);
                }
            }
            else
            {
                if(x[i]&(1<<t))
                {
                    //b-a+1<=sum[b]-sum[a-1]<=b-a+1;
                    //sum[b]-sum[a-1]>=b-a+1;
                    //sum[a-1]-sum[b]>=a-b-1;
                    add(a-1,b,b-a+1);
                    add(b,a-1,a-b-1);
                    sum[a]++;sum[b+1]--;
                }
                else
                {
                    //0<=sum[b]-sum[a-1]<=b-a;
                    //sum[b]-sum[a-1]>=0;
                    //sum[a-1]-sum[b]>=a-b;
                    add(a-1,b,0);
                    add(b,a-1,a-b);
                }
            }
        }
        for(int i=1;i<=n;i++)
            sum[i]+=sum[i-1];
        for(int i=1;i<=n;i++)
            if(sum[i])sum[i]=1;
        for(int i=1;i<=n;i++)
            sum[i]+=sum[i-1];
        for(int i=1;i<=n;i++)
        {
            //sum[i]-sum[0]
            add(0,i,sum[i]);
        }
        Dij();
        //for(int i=1;i<=n;i++)
            //d[i]=-d[i];
        for(int i=1;i<=n;i++)
        {
            ans[i]=ans[i]+(d[i]-d[i-1])*(1<<t);
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d%c",ans[i],i==n?'\n':' ');
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值