现在的位置: 首页 > 综合 > 正文

2013长沙网络赛J题 Candies(差分约束或数学规律)#by zh

2018年04月23日 ⁄ 综合 ⁄ 共 3261字 ⁄ 字号 评论关闭

这题真心神坑,刚拿到这个题,想了一会,感觉可以用差分约束做,写完了之后稍微调了一下,交上去WA了,改了一会也还是WA,以为是算法错了。然后发现是有规律的,又改用数学方法去做,写的有些挫,出数据调了不少bug,但是还是WA到死,最后也没做出来。今天又想了一下,队友发现每个点取值的范围是非负,而不是0到10000,不得不吐槽题意真心坑,然后把之前的两个代码都去掉10000的约束以后都过了。读题是硬伤啊……

差分约束:分别维护前i个人拥有石头个数的最大可能值和最小可能值,第i个人可能的最大数值就是dismax[i]-dismin[i-1]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
#define MAXN 100005
int dismax[MAXN],dismin[MAXN];
int vis[MAXN];
const int INF=0x3f3f3f3f;
struct Node
{
    int v,w;
    Node(int a,int b){v=a,w=b;}
};
int n;
vector<Node> gmin[MAXN],gmax[MAXN];
void spfamax()
{
    for(int i=0;i<=n;i++)
        dismax[i]=INF;
    memset(vis,0,sizeof(vis));
    dismax[0]=0;
    queue<int> q;
    q.push(0);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        int len=gmax[u].size();
        for(int i=0;i<len;i++)
        {
            int v=gmax[u][i].v,w=gmax[u][i].w;
            if(dismax[v]>dismax[u]+w)
            {
                dismax[v]=dismax[u]+w;
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
void spfamin()
{
    for(int i=0;i<=n;i++)
        dismin[i]=-INF;
    memset(vis,0,sizeof(vis));
    dismin[0]=0;
    queue<int> q;
    q.push(0);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        int len=gmin[u].size();
        for(int i=0;i<len;i++)
        {
            int v=gmin[u][i].v,w=gmin[u][i].w;
            if(dismin[v]<dismin[u]+w)
            {
                dismin[v]=dismin[u]+w;
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    //freopen("test.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<=n;i++)
            gmin[i].clear(),gmax[i].clear();
        for(int i=1;i<=n;i++)
        {
            gmax[i].push_back(Node(i-1,0));
            gmin[i-1].push_back(Node(i,0));
        }
        for(int i=1;i<=n;i++)
        {
            int temp;
            scanf("%d",&temp);
            if(temp!=-1)
            {
                gmax[i-1].push_back(Node(i,temp));
                gmax[i].push_back(Node(i-1,-temp));
                gmin[i-1].push_back(Node(i,temp));
                gmin[i].push_back(Node(i-1,-temp));
            }
        }
        for(int i=1;i<=n;i++)
        {
            int w;
            scanf("%d",&w);
            int u=max(0,i-2),v=min(n,i+1);
            gmax[u].push_back(Node(v,w));
            gmax[v].push_back(Node(u,-w));
            gmin[u].push_back(Node(v,w));
            gmin[v].push_back(Node(u,-w));
        }
        spfamax();
        spfamin();
        int q;
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            int temp;
            scanf("%d",&temp);
            temp++;
            printf("%d\n",dismax[temp]-dismin[temp-1]);
        }
    }
}

数学规律:3,6,9,……都可以算出来,然后第1项可以推4,7,10……,第2项可以推5,8,11……,前两项是固定的,设第一项为x,第二项为num[1]-x,add维护

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAXN 100005
int num[MAXN];
int tot[MAXN];
int value[MAXN];
int add[MAXN];
int main()
{
    //freopen("test.txt","r",stdin);
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(value,0,sizeof(value));
        memset(add,0,sizeof(add));
        for(int i=1; i<=n; i++)
            scanf("%d",&tot[i]);
        for(int i=1; i<=n; i++)
            scanf("%d",&num[i]);
        int l=0,r=num[1],addx=0,addy=0;
        bool ok=false;
        for(int i=1; i<=n; i++)
        {
            if(i%3==1)
            {
                if(i>3)
                    addx+=num[i-1]-num[i-2];
                if(tot[i]!=-1)
                {
                    value[1]=tot[i]-addx;
                    value[2]=num[1]-value[1];
                    ok=true;
                }
                else
                {
                    //r=min(r,10000-addx);
                    l=max(l,-addx);
                }
                add[i]=addx;
            }
            else if(i%3==2)
            {
                if(i>3)
                    addy+=num[i-1]-num[i-2];
                if(tot[i]!=-1)
                {
                    value[1]=num[1]+addy-tot[i];
                    value[2]=num[1]-value[1];
                    ok=true;
                }
                else
                {
                    r=min(r,num[1]+addy);
                    //l=max(l,num[1]+addy-10000);
                }
                add[i]=addy;
            }
            else
            {
                value[i]=value[i-3]+num[i-1]-num[i-2];
            }
        }
        if((n-2)%3!=0)
        {
            ok=true;
            if((n-2)%3==1)
            {
                value[1]=num[n-1]-num[n]-add[n-2];
                value[2]=num[1]-value[1];
            }
            else
            {
                value[1]=num[1]+add[n-2]-(num[n-1]-num[n]);
                value[2]=num[1]-value[1];
            }
        }
        int q;
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            int temp;
            scanf("%d",&temp);
            if((temp+1)%3==0)
                printf("%d\n",value[temp+1]);
            else if(ok)
            {
                printf("%d\n",value[(temp+1)%3]+add[temp+1]);
            }
            else
            {
                if((temp+1)%3==1)
                    printf("%d\n",r+add[temp+1]);
                else printf("%d\n",num[1]-l+add[temp+1]);
            }
        }
    }
}

抱歉!评论已关闭.