codeforces 567E President and Roads Dijikstra

题意:

一张有向图(可能有环),给定起始点以及终点,对于所有边来说,如果起始点到终点的所有最短路都经过该边,那么输出YES,否则如果我们可以降低该边的权值使得所有的最短路都经过该边的话输出CAN x (x为降低的最小权值),如果降低也不能让所有的最短路经过他的话,那么输出NO。
注意任意时刻边权是正整数。


解析:

我们先正向跑一边最短路并记录起始点到每个点的最短路以及最短路条数,注意最短路条数可能爆long long,所以我们需要自行选取一个质数取模。
然后再反向跑一边最短路并记录终点到每个点的反向最短路以及最短路的条数,同样需要取模。
接下来我们枚举每一条边。
我们可以发现,如果该边在所有的最短路上的话,那么起始点到该边的起始点的最短路加上该边权值再加上终点到该边终点的反向最短路的值恰好等于起始点到终点的最短路距离。
并且还有额外的条件:即起始点到该边起始点的最短路条数乘以终点到该边的终点的反向最短路条数等于起始点到终点的最短路条数。
所以如果满足了这两个条件,那么直接输出YES。
否则我们观察调整该边的权值是否可以满足他在所有的最短路上。
第一种情况:该边在某些起点到终点的最短路上,但不在起点到终点的所有最短路上。
那么显然如果该边的权值只要减小1便能使他在所有的最短路上。
所以只需要判断该边权值是否大于1即可。
第二种情况:该边不在任意一条最短路上。
那么我们需要知道经过该边的起点到终点的最短路距离。
如果该边权值大于这个距离与起点到终点的最短路距离之差加一的话,显然可以降低,否则不能降低。


需要特殊注意的:
因为这里是CF :)
所以模数你要是取了1000000007的话,那么你就会体验到WA ON TEST 104 的快感:)
所以我们不妨取宋爷数——5462617


代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
#define mod 5462617
#define INF 0x3f3f3f3f3f3f3f3fll
using namespace std;
typedef long long ll;
int n,m,s,t;
int head[N],cnt,rhead[N],rcnt;
ll count1[N],count2[N];
struct node
{
    int from,to;
    ll val;
    int next;
}edge[N<<1],redge[N<<1];
struct Line
{
    int u,v;
    ll val;
}l[N];
void init()
{
    memset(head,-1,sizeof(head));
    memset(rhead,-1,sizeof(rhead));
    rcnt=cnt=1;
}
void edgeadd(int from,int to,ll val)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val;
    edge[cnt].next=head[from],head[from]=cnt++;
}
void redgeadd(int from,int to,ll val)
{
    redge[rcnt].from=from,redge[rcnt].to=to,redge[rcnt].val=val;
    redge[rcnt].next=rhead[from],rhead[from]=rcnt++;
}
struct Element
{
    int no;
    ll val;
    friend bool operator < (Element a,Element b)
    {
        if(a.val==b.val)return a.no>b.no;
        return a.val>b.val;
    }
};
int v[N];
ll dis1[N],dis2[N];
ll mindis;
void dijikstra(ll *count,ll *dis,int *head,node *edge,int S)
{
    for(int i=1;i<=n;i++)dis[i]=INF;
    memset(v,0,sizeof(v));
    priority_queue<Element>q;
    Element fir;
    fir.no=S,fir.val=0;
    q.push(fir);
    dis[S]=0;
    count[S]=1;
    while(!q.empty())
    {
        Element u=q.top();
        q.pop();
        if(v[u.no])continue;
        v[u.no]=1;
        for(int i=head[u.no];i!=-1;i=edge[i].next)
        {
            int to=edge[i].to;
            if(dis[u.no]+edge[i].val==dis[to])
            {
                count[to]=(count[to]+count[u.no])%mod;
            }else if(dis[u.no]+edge[i].val<dis[to])
            {
                dis[to]=dis[u.no]+edge[i].val;
                count[to]=count[u.no];
                Element pus;
                pus.no=to,pus.val=dis[to];
                q.push(pus);
            }
        }
    }
}
int main()
{
    init();
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        ll val;
        scanf("%d%d%I64d",&u,&v,&val);
        edgeadd(u,v,val);
        redgeadd(v,u,val);
        l[i].u=u,l[i].v=v,l[i].val=val;
    }
    dijikstra(count1,dis1,head,edge,s);
    dijikstra(count2,dis2,rhead,redge,t);
    mindis=dis1[t];
    for(int i=1;i<=m;i++)
    {
        int u=l[i].u,v=l[i].v;
        ll val=l[i].val;
        if(dis1[u]+dis2[v]+val==mindis)
        {
            if(count1[u]*count2[v]%mod==count1[t])
                puts("YES");
            else if(val>1)puts("CAN 1");
            else puts("NO");
        }else if(dis1[u]+dis2[v]+val>mindis)
        {
            if(val>dis1[u]+dis2[v]+val-mindis+1)
                printf("CAN %I64d\n",dis1[u]+dis2[v]+val-mindis+1);
            else puts("NO");
        }
    } 
}
### Codeforces 887E Problem Solution and Discussion The problem **887E - The Great Game** on Codeforces involves a strategic game between two players who take turns to perform operations under specific rules. To tackle this challenge effectively, understanding both dynamic programming (DP) techniques and bitwise manipulation is crucial. #### Dynamic Programming Approach One effective method to approach this problem utilizes DP with memoization. By defining `dp[i][j]` as the optimal result when starting from state `(i,j)` where `i` represents current position and `j` indicates some status flag related to previous moves: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = ...; // Define based on constraints int dp[MAXN][2]; // Function to calculate minimum steps using top-down DP int minSteps(int pos, bool prevMoveType) { if (pos >= N) return 0; if (dp[pos][prevMoveType] != -1) return dp[pos][prevMoveType]; int res = INT_MAX; // Try all possible next positions and update 'res' for (...) { /* Logic here */ } dp[pos][prevMoveType] = res; return res; } ``` This code snippet outlines how one might structure a solution involving recursive calls combined with caching results through an array named `dp`. #### Bitwise Operations Insight Another critical aspect lies within efficiently handling large integers via bitwise operators instead of arithmetic ones whenever applicable. This optimization can significantly reduce computation time especially given tight limits often found in competitive coding challenges like those hosted by platforms such as Codeforces[^1]. For detailed discussions about similar problems or more insights into solving strategies specifically tailored towards contest preparation, visiting forums dedicated to algorithmic contests would be beneficial. Websites associated directly with Codeforces offer rich resources including editorials written after each round which provide comprehensive explanations alongside alternative approaches taken by successful contestants during live events. --related questions-- 1. What are common pitfalls encountered while implementing dynamic programming solutions? 2. How does bit manipulation improve performance in algorithms dealing with integer values? 3. Can you recommend any online communities focused on discussing competitive programming tactics? 4. Are there particular patterns that frequently appear across different levels of difficulty within Codeforces contests?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值