【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 待续

相关文章
相关标签/搜索