2020牛客NOIP赛前集训营-普及组(第六场)

A 七七七七

分析

由于每次的答案的增长是以指数增长的,所以直接枚举日期的复杂度为 。那就直接暴力枚举就可以了。总的复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
int read() {int x;scanf("%d",&x);return x;}
int main() {
    int n = read();
    int sum = 0;
    for(int i = 1,c = 1;;i = i * 7,c++) {
        sum += i;
        if(sum >= n) {
            cout << c << endl;
            return 0;
        }
    }
}

B 平面旅行

分析

我们可以发现,任意两个节点的距离一定是,不经过中间节点直接到达。所以对于一个节点来说,对答案的贡献为 其中 表示特殊节点。 总的复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5100;
int read() {int x;scanf("%d",&x);return x;}
struct Node{int x,y;}s[N];
int p[N];
int dis(int a,int b) {
    return abs(s[a].x-s[b].x) + abs(s[a].y-s[b].y);
}
int main() {
    int n = read(),m = read();
    for(int i = 1;i <= n;i++) {
        s[i].x = read();s[i].y = read();
    }
    for(int i = 1;i <= m;i++) p[i] = read();
    int ans = 0;
    for(int i = 2;i <= n;i++) {
        int res = dis(i,i-1);
        for(int j = 1;j <= m;j++) res = min(res,dis(i,p[j]));
        ans += res;
    }
    cout << ans << endl;
}

C 小球下落

分析

对于所有球来说,我们并不在意球的标号。只要需要最后占据的是最优答案的那几个节点。我们发现不管怎样我们是想球越低越好的,所以可以开一个桶,桶中保存最大值。那么每次遇到一个 我们就弹出桶中的最大值。而如果我们发现有 分开了上下边界,我们就必须把桶情况,由于宽度为 。我们可以枚举 的每种情况。加上堆的复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 310000;
int read() {int x;scanf("%d",&x);return x;}
char ch[N][2];
priority_queue<int> heap;
int n;
void solve() {while(!heap.empty()) heap.pop();}
int main() {
    scanf("%d\n",&n);int ans = 0;
    for(int i = 1;i <= n;i++) scanf("%s",ch[i]);
    ch[n + 1][1] = ch[n + 1][0] = 'x';
    for(int i = n;i >= 1;i--) {
        int x = 0;
        if(ch[i][0] == 'x' && ch[i][1] == 'x') solve();else
        if(ch[i][0] == 'x' && ch[i+1][1] == 'x') solve();else 
        if(ch[i+1][0] == 'x' && ch[i][1] == 'x') solve();
        for(int j = 0;j < 2;j++) if(ch[i][j] != 'x') heap.push(i);
        for(int j = 0;j < 2;j++) {
            if(ch[i][j] == 'o') {
                ans += heap.top() - i;
                heap.pop();
            }
        }
    }
    cout << ans << endl;
    return 0;
}

D 自由世界

分析

类似 题的分析,我们的答案仍然为 ,只是 现在表示为最短路,而不是直接距离。那么我们跑 次最短路就可以了。那么总的复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5100;
int read() {int x;scanf("%d",&x);return x;}
#define pii pair<int,int>
vector<pii> G[N];
priority_queue<pii> heap;
int n,p[N],dis1[N],dis2[N],m,k;
void solve(int *dis) {
    static bool vis[N];
    memset(vis,0,sizeof(vis));
    while(!heap.empty()) {
        int x = heap.top().second;heap.pop();
        if(vis[x]) continue;
        vis[x] = 1;
        for(auto e : G[x]) {
            int y = e.first,w = e.second;
            if(dis[y] > dis[x] + w) {
                dis[y] = dis[x] + w;
                heap.push(pii(-dis[y],y));
            }
        }
    }
}
int main() {
    n = read();m = read();k = read();
    for(int i = 1,a,b,c;i <= m;i++) {
        a = read();b = read();c = read();
        G[a].push_back(pii(b,c));G[b].push_back(pii(a,c));
    }
    for(int i = 1;i <= k;i++) p[i] = read();
    memset(dis1,0x3f,sizeof(dis1));
    for(int i = 1;i <= k;i++) {
        dis1[p[i]] = 0;heap.push(pii(0,p[i]));
    }
    solve(dis1);int ans = 0;
    for(int i = 2;i <= n;i++) {
        memset(dis2,0x3f,sizeof(dis2));
        dis2[i - 1] = 0;heap.push(pii(0,i - 1));
        solve(dis2);
        ans += min(dis1[i],dis2[i]);
    }
    cout << ans << endl;
}