T1 0 pts

T2 10pts

T3 0 pts

好文推荐

图论中的二分

关于一个图中是否存在负环


1383: 小奇挖矿

___可以发现,当前的决策只对后面的开采有影响,且剩余耐久度与之后的开采收益成正比.

___如果倒着考虑这个问题,得出i-n的星球"1"耐久度所能获得的最大收益,从后往前dp,得出最大值最后乘w就是答案
考试技巧:zz的我懒得打暴力,结果dp写挂了……下次还是打包里吧,毕竟
** 绵阳市第三医院委提醒您:骗分千万条,暴力第一条,代码不规范,欧阳两行泪 **

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dwn(i,a,b) for(int i=a;i>=b;i--)
#define N 100001
using namespace std;
double k,c,ans;
int n,w;
int op[N],a[N];

int main()
{
    //freopen("input.txt","r",stdin);
    scanf("%d%lf%lf%d",&n,&k,&c,&w);
    rep(i,1,n)
        scanf("%d%d",&op[i],&a[i]);
    k=1-0.01*k,c=1+0.01*c;
    dwn(i,n,1)
    {
        if(op[i]==1)
            ans=max(ans,ans*k+a[i]);
        else
            ans=max(ans,ans*c-a[i]);
    }
    printf("%.2f",ans*w);
    return 0;
}

1384: 小奇的数列

90pts 做法(前缀和+抽屉原理优化)

  • 抽屉原理:如果询问的区间长度>=mod的话,一定有两个前缀和相减等于0,那么直接输出0即可

考试技巧:
我写的10 pts没加任何优化……抽屉原理送您80pts

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

ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int n,m;
ll sum[500005];

int main()
{
    freopen("input.txt","r",stdin);
    scanf("%d%d",&n,&m);
    rep(i,1,n)
        sum[i]=sum[i-1]+read();
    int l,r,mod;
    rep(i,1,m)
    {
        l=read(),r=read(),mod=read();
        if(r-l+1>mod)puts("0");//抽屉原理
        else
        {
            int ans=mod;//相当于赋了一个极大值
            rep(i,l,r)
                rep(j,i,r)
                    ans=min((int)((sum[j]-sum[i-1])%mod),ans);
                    //强行转int
            printf("%d\n",ans);
        }
    }
    return 0;
}

1385: 小奇回地球

二分 && dfs反向染色 && SPFA+判负环

解析

1.跑有负边图的最短路只能SPFA。

2.由于t和答案同增同减,具有单调性。我们可以二分t来取符合条件的最小距离。

3.问题出在对负环的处理上。一开始想的是,有负环直接判不合法。然而如果通过负环不能到达n号点,这个负环实际上可以忽略。所以开头建反边,从n跑dfs看能到达哪些点,只对这些点跑最短路即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int ans,n,m,cnt,mid;
int head[10000],used[105],dis[105],mark[105];

int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

struct node{
    int v,w,nxt;
}e[10000];

vector<int>G[105];

void add(int u,int v,int w)
{
    e[++cnt].v=v;
    e[cnt].nxt=head[u];
    e[cnt].w=w;
    head[u]=cnt;
}

int SPFA()
{
    memset(used,0,sizeof(used));
    rep(i,1,n)dis[i]=INT_MAX;
    used[1]=1;
    queue<int>Q;
    Q.push(1);
    dis[1]=0;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        if(used[u]>n)
            return false;//负环
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!mark[v])continue;
            int dist=e[i].w+mid;//要加上偏移量
            if(dis[v]>dis[u]+dist)
            {
                dis[v]=dis[u]+dist;
                used[v]++;
                Q.push(v);
            }
        }
    }
    if(dis[n]>=0 && dis[n]!=INT_MAX)
        return true;
    else
        return false;
}

void DFS(int cur)
{
    mark[cur]=1;
    for(int i=0;i<G[cur].size();i++)
    {
        if(mark[G[cur][i]])continue;
        DFS(G[cur][i]);
    }
}

int main()
{
    freopen("input.txt","r",stdin);
    int T;
    T=read();
    while(T--)
    {
        cnt=0;ans=-1;
        memset(head,0,sizeof(head));
        memset(e,0,sizeof(e));
        memset(mark,0,sizeof(mark));
        int l=-INT_MAX,r=INT_MAX;
        n=read(),m=read();
        rep(i,1,m)
        {
            int x,y,z;
            x=read(),y=read(),z=read();
            add(x,y,z);
            G[y].push_back(x);
        }
        l=-100000,r=100000;
        DFS(n);
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(SPFA())
            {
                ans=dis[n];
                r=mid-1;
            }
            else l=mid+1;
        }
        printf("%d\n",ans);
        rep(i,1,n)G[i].clear();
    }
    return 0;
}
01-20 08:38