【2020-9-06比賽】 題解

模擬賽直接昇天 ios

100 + 100 + 100 + 30 秒變 50 + 30 + 0 + 30數組

自身的問題仍是有點多ide


A. 簡單遊走

有一張 n 個點, m條邊的無向圖,點從  1到  n標號。ui

時刻 0時,你在結點1 。你須要用最少的時間從結點  1走到結點n 。經過m條邊中的每一條都要花必定的時間。spa

每一個結點會有可能在某些時刻被限制。一個結點 x 在時刻T被限制,意味着這個結點的人在時刻T不能從這個點x走出去。3d

你只能在整數時刻進出某個結點,一個結點能夠逗留任意非負整數時間。code

如今,請問你最少須要多少時間能從結點 1走到結點n blog

 

能夠看出確定越早到一個點越優 在這個點上等再到這個點的全部連點 和  到連點後再等待出點 是同一個道理,咱們記錄每一個點的最先到達時間,遊戲

用最先出點時間更新它的連點 跑一遍最短路就好了 同時 數組 須要 開大 且 開始定義的最大值要很大 否則直接wa了。it

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#define f(i, a, b) for (long long i = a; i <= b; i++)
using namespace std;
priority_queue<pair<long long, long long> > QAQ;
long long n, m, k, begi, fina, v, head[100100], d[100100];
bool tim[5000][5000];
bool visit[100010];
struct QWQ {
    long long to, next, value;
} edge[100100];
void make(long long a, long long b, long long c) {
    edge[++edge[0].value].to = b;
    edge[edge[0].value].value = c;
    edge[edge[0].value].next = head[a];
    head[a] = edge[0].value;
}
void dij() {
    QAQ.push(make_pair(0, 1));
    d[1] = 0;
    while (QAQ.size()) {
        long long num = QAQ.top().second;
        QAQ.pop();
        if(visit[num]) continue;
        visit[num] = 1;
        long long p = d[num];
        while(tim[num][p])p++;
            for (long long i = head[num]; i; i = edge[i].next) {
                if (p + edge[i].value < d[edge[i].to]) {
                            d[edge[i].to] = p + edge[i].value;
                            QAQ.push(make_pair(-d[edge[i].to], edge[i].to));
                        }
                    }
                }
    }

int main() {
    freopen("travel.in", "r", stdin);
    freopen("travel.out", "w", stdout);
    scanf("%lld%lld", &n, &m);
    f(i, 1, m) {
        scanf("%lld%lld%lld", &begi, &fina, &v);
        make(begi, fina, v);
        make(fina, begi, v);
    }
    f(i, 1, n) {
        scanf("%lld", &k);
        long long t;
        f(j, 1, k) {
            scanf("%lld", &t);
            tim[i][t] = 1;
        }
        d[i] = 1e16;
    }
    dij();
    printf("%lld", d[n]);
    return 0;
}
View Code

 

 


 

B. 卡牌選取

校慶志願者小Z在休息時間和同窗們玩卡牌遊戲。一共有n張卡牌,每張卡牌上有一個數Ai,每次能夠從中選出k張卡牌。一種選取方案的幸運值爲這k張卡牌上數的異或和。小Z想知道全部選取方案的幸運值之和除以998244353的餘數。
 
咱們考慮使用二進制 對於 二進制的每一位 只有 奇數個1 異或 纔是有意義的 因此咱們只要對每一位的數字統計 n 個 0,1 有多少種 k 個 數的組合有奇數個1
 
(設此爲全部的數的的和爲sum)此位爲第i位 選出 j 個 1 則剩下 k - j 個 0 

 

#include<cstdio>
#include<algorithm>
using namespace std;
const long long mo=998244353;
const int MAXN=100000+5;
long long a[MAXN],inv[MAXN],fact[MAXN];
long long power(long long a,long long b)
{
    long long t=1,y=a%mo;
    while (b)
    {
        if (b&1)
            t=t*y%mo;
        y=y*y%mo;
        b>>=1;
    }
    return t;
}
int main()
{
    freopen("card.in","r",stdin);
    freopen("card.out","w",stdout);
    int n,k;
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)  
        scanf("%d",&a[i]);
    fact[0]=inv[0]=1;
    for (int i=1;i<=n;i++)
    {
        fact[i]=fact[i-1]*i%mo;
        inv[i]=power(fact[i],mo-2);
    }
    int sum;
    long long ans=0;
    for (int i=0;i<=30;i++)
    {
        sum=0;
        for (int j=1;j<=n;j++)
                sum+=((a[j]>>i)&1);
        for (int j=1;j<=min(k,sum);j++)
            if (k-j<=n-sum&&j&1)
                ans=(ans+fact[sum]*inv[j]%mo*inv[sum-j]%mo*fact[n-sum]%mo*inv[k-j]%mo*inv[n-sum-k+j]%mo*(1ll<<i)%mo)%mo;
    }
    printf("%lld",ans);
    return 0;
}
View Code

 

 C D 待續

相關文章
相關標籤/搜索