1. 程式人生 > 其它 >牛牛選路徑(牛客)

牛牛選路徑(牛客)


感覺很像小時候玩的一個遊戲《一筆成畫》
保證圖連通,每條邊都經過奇數次,等價於每條邊只經過一次
對於重邊可以不考慮,1->3,3->1,再走回來就行了
發現路徑是什麼樣的不重要,重要的是起點和終點
發現起點和終點的度數一定是奇數
起點最後會引出一條出邊
終點最後會收回一條入邊
且起點和終點可以互換
所以預處理每個點的度數,判斷是否為奇數
特別的,如果所有的度數都為偶數,則構成一個環,只需要找到點權最小的即可
否則,起點和終點一定成雙成對,有多少對起終點就有多少條路徑
統計答案時:
設a<b<c<d
很容易證明ad+bc<ab+cd

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iomanip>
#include<bitset>
#include<climits>
#ifdef _MSC_VER
#  include <intrin.h>
#  define __builtin_popcount __popcnt
#  define __lg log2
#endif
#define N 100010
#define M 200010
#define INF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define mod 998244353
using namespace std;
ll n, m, a[N], d[N],s[N],cnt,ans;
bool cmp(ll x, ll y) {
    return a[x] < a[y];
}
int main() {
    scanf("%lld%lld", &n, &m);
    for (ll i = 1; i <= n; ++i)
        scanf("%lld", &a[i]);
    for (ll i = 1; i <= m; ++i) {
        ll u, v;
        scanf("%lld%lld", &u, &v);
        d[u]^=1;
        d[v]^=1;
    }
    for (ll i = 1; i <= n; ++i)
        if (d[i])
            s[++cnt] = i;
    if (!cnt) {
        ll mi = INF;
        for (ll i = 1; i <= n; ++i)
            mi = min(mi, a[i]);
        printf("%lld\n", mi * mi % mod);
    }
    else {
        sort(s + 1, s + 1 + cnt, cmp);
        for (ll i = 1; i <= cnt / 2; ++i)
            ans = (ans + a[s[i]] * a[s[cnt - i + 1]] % mod) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}