7.18


今天现场只过了一道题==有点尴尬


7.17场训练地址

B题:
题意:你有x块饼干,要分给n个人,以5个人为例,分的顺序是1,2,3,4,5,4,3,2,1,2。。。问最后每个人会分得多少块饼干。

解法:简单的模拟,循环节长度为n*2-1,注意当n==1的时候的特例情况

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll x;
ll n, T, re, pe;
ll a[100000 + 5];

void add() {
    if (re > n) {
        int more = re - n;
        for (int i = 1; i <= n; i++) {
            if (i == 1 || i == n || i < n - more)a[i] += 1;
            else a[i] += 2;
        }
    }
    else {
        for (int i = 1; i <= re; i++) {
            a[i] += 1;
        }
    }
    return;
}

int main() {
    scanf("%lld", &T);
    while (T--) {
        memset(a, 0, sizeof(a));
        scanf("%lld%lld", &x, &n);
        ll mod = n * 2 - 2;
        if (n == 1) {
            printf("%lld
", x); 
            continue;
        }
        re = x%mod, pe = x / mod;
        if (pe > 0) {
            for (ll i = 1; i <= n; i++) {
                if (i == 1 || i == n)a[i] += pe;
                else a[i] += 2*pe;
            }
            add();
        }
        else add();
        printf("%lld", a[1]);
        for (ll i = 2; i <= n; i++) {
            printf(" %lld", a[i]);
        }printf("
");
    }
    return 0;
}

7.18场地址
B题:
题意:给定一个序列a[n],问在1~2^60的范围内有多少个数字s满足(a[i]^s)<=(a[i+1]^s)

解法:考虑这样的情况:100100100,100101100,可以看出来,当两个数位相同的时候,无论怎样异或,他们的值都不会变,因此我们从高位看到低位,当出现第一个不同的位置的时候,如果要保证后者的值总是大于前者,上面的情况,我们就需要将s的那一位置换成0,反之则将其置换为1,接下来统计所有a[i]~a[i+1]的数对,每个都寻找这样的数位,最后统计有多少个数位不需要替换。

每有一个数位不需要替换,就表明有两种情况(这个数位上0或1),因此答案总数就是2^n;

#include <cstdio>
#include <algorithm>
#define maxn 100
#define ll long long
using namespace std;
ll a[maxn], N, cnt[maxn];
int main()
{
    ll i, j, last, now, ans=1;
    scanf("%lld%lld",&N,&last);
    for(i=0;i<=59;i++)cnt[i]=-1;
    for(i=2;i<=N;i++,last=now)
    {
        scanf("%lld",&now);
        for(j=59;j>=0;j--)
            if((last^now)&(1ll<<j))
            {
                if(last&(1ll<<j))
                {
                    if(cnt[j]==-1)cnt[j]=1;
                    if(cnt[j]==0){printf("0");return 0;}
                }
                else
                {
                    if(cnt[j]=-1)cnt[j]=0;
                    if(cnt[j]==1){printf("0");return 0;}
                }
                break;
            }
    }
    for(i=0;i<=59;i++)if(cnt[i]==-1)ans<<=1;
    printf("%lld",ans);
    return 0;
}

C题:
题意:模拟acm比赛的积分制,每支队伍先看过题数,越多优先级越高,排名越靠前;如果过题数相等,我们就看罚时,罚时越少越靠前,一共有n只队伍,每次输入过题的队伍和罚时,询问队伍1的排名;

解法:这道题的代码非常有特色,具体看代码就好,有好多可以学的。

//熊大佬就是强!!!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 1e6;
struct node {int num, pen;};
node sc[maxn];

node operator+(node lhs, node rhs) { return { lhs.num + rhs.num, lhs.pen + rhs.pen }; }
bool operator < (node lhs, node rhs) { return lhs.num < rhs.num || (lhs.num == rhs.num&&lhs.pen > rhs.pen); }
bool operator <=(node lhs, node rhs) { return !(rhs < lhs); }

multiset<node>s;//表示优先级比主队高的队的集合

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int t, p;
        scanf("%d%d", &t, &p); t--;
        node a{ 1,p };
        if (t) {
            node& os = sc[t], ns = sc[t] + a;
            //os为编号为t的队当前的状态,ns为它回答完这次问题之后的状态
            if (sc[0] < os) { s.erase(s.lower_bound(os)); s.insert(ns); }
            //如果这个队的优先级要比0队高,那么就维护该队的信息
            //之所以要比较上面那一部的目的是可能在进行这一步的时候主队的状态已经更新过多次了,集合内不能出现重复的队伍
            else if (sc[0] < ns) { s.insert(ns); }
            //如果新状态要比主队高,直接入集合
            os = ns;
        }
        else {
            sc[0] = sc[0] + a;
            //删除优先级比更新后的主队低的队伍
        }
        printf("%d
", s.size() + 1);
    }
    return 0;
}

K题:
题意:给定一张有权无向图,每个结点有一个值a[i],只有特定的时间段可以离开结点i,这个时间就是[0,a[i]),[2*a[i],3*a[i]),[3*a[i], 4*a[i])…,问从s到t的最短路径为多少

解法:刚开始觉得是爆搜,后来才知道标解就是修改一下spfa即可,当访问到当前结点的时候我们根据是否可以离开来维护它的时间(距离)值即可
做题不能自己会什么方法,就只会用什么方法,要灵活,不能总是一招鲜想吃遍天

#include<stdio.h>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e4 + 5;
int dis[maxn], flag[maxn], a[maxn];
int s, t, n;
const int inf = 99999999;
struct edge {
    int v, w;
};
vector<edge>_a[maxn];
void add_edge(int u, int v, int w) {
    edge tmp;
    tmp.v = v;
    tmp.w = w;
    _a[u].push_back(tmp);
}
void spfa(int s) {
    queue<int>q;
    q.push(s);
    memset(dis, 0x3f, sizeof(dis));
    memset(flag, 0, sizeof(flag));
    dis[s] = 0; flag[s] = true;
    int now;
    while (!q.empty()) {
        int u = q.front(); q.pop(); flag[u] = false;
        int x = dis[u] / a[u];
        now = dis[u];
        if (x % 2 == 1)  now = (x + 1)*a[u];
        for (int i = 0; i < _a[u].size(); i++) {//扫描所有邻接点
            if (dis[_a[u][i].v] > now + _a[u][i].w) {
                dis[_a[u][i].v] = now + _a[u][i].w;
                if (!flag[_a[u][i].v]) {
                    q.push(_a[u][i].v);
                    flag[_a[u][i].v] = true;
                }
            }
        }
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int m, tmp;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &tmp);
            a[i] = tmp;
        }
        int u, v, w;
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            add_edge(u, v, w); add_edge(v, u, w);
        }
        scanf("%d%d", &s, &t);
        spfa(s);
        printf("%d
",dis[t]);
        for (int i = 0; i <= n; i++) {
            _a[i].clear();
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/romaLzhih/p/9489808.html