牛牛选路径(牛客)


感觉很像小时候玩的一个游戏《一笔成画》
保证图连通,每条边都经过奇数次,等价于每条边只经过一次
对于重边可以不考虑,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;
}
原文地址:https://www.cnblogs.com/wzxbeliever/p/15693279.html