CCPC-Wannafly Summer Camp 2019 全记录

Posted izcat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCPC-Wannafly Summer Camp 2019 全记录相关的知识,希望对你有一定的参考价值。

 // 7.19-7.29 东北大学秦皇岛校区十天训练营,题目都挂在了Vjudge上。训练期间比较忙,没空更博总结,回来继续补题消化。

 // https://vjudge.net/contest/312902

https://vjudge.net/contest/313217

https://vjudge.net/contest/313584

https://vjudge.net/contest/314412

https://vjudge.net/contest/314730

https://vjudge.net/contest/314974

Day1

这天授课主题是简单图论,节奏挺好,wls两小时理完图论里的基本知识点。

下午的赛题就偏入门了(简单图论无疑),只涉及到最短路问题和简单的搜索以及一些奇怪的技巧。(差分约束呢?最小生成树呢?强连通分量呢?)

A - Jzzhu and Cities (补)

把火车线路加上跑Dijkstra就好了,标记火车线路,相等时也要push。在最短路上的火车线路不能被取消,剩下的全部能取消。

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 200010;
struct Edge 
    int to;
    bool istrain;
    ll w;
    Edge(int v, bool is, ll ww):to(v), istrain(is), w(ww)
    bool operator<(const Edge& a)const 
        if(w==a.w) return istrain;  // 非火车节点先更新
        return w > a.w;
    
;
vector<Edge> G[maxn];

bool vis[maxn];
int d[maxn];

int Dijkstra() 
    memset(d, 0x3f, sizeof(d));
    memset(vis, 0, sizeof(vis));
    d[1] = 0;
    int res = 0;

    priority_queue<Edge> q;
    q.push(Edge(1, 0, 0));
    while(!q.empty()) 
        Edge tmp = q.top(); q.pop();
        int u = tmp.to;
        if(vis[u]) continue;

        vis[u] = 1;
    //    d[u] = tmp.w;
        if(tmp.istrain) ++res;

        for(int i=0;i<G[u].size();i++) 
            int v = G[u][i].to;
            if(!vis[v] && d[v]>=d[u]+G[u][i].w) 
                d[v] = d[u] + G[u][i].w;
                q.push(Edge(v, G[u][i].istrain, d[v]));
            
        

    
    return res;



int main() 
    int n, m, k;
    cin>>n>>m>>k;
    int u, v, w;
    for(int i=0;i<m;i++) 
        scanf("%d %d %d", &u, &v, &w);
        G[u].push_back(Edge(v, 0, w));
        G[v].push_back(Edge(u, 0, w));
    
    for(int i=0;i<k;i++) 
        scanf("%d %d", &v, &w);
        G[1].push_back(Edge(v, 1, w));
        // G[v].push_back(Edge(1, 1, w));
    

    printf("%d\\n", k-Dijkstra());

    return 0;
View Code

 

B - Phillip and Trains 

BFS 注意打标记!!!(虽然只是3*100的地图也要爆内存!)

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n, k, sx;
char mp[3][110];
bool vis[3][110];
struct node 
    int x, y;
    node(int _x, int _y):x(_x), y(_y) 
;

bool check(int x, int y) 
    if(x<0 || x>2)
        return false;
    if(y>=n)
        return true;
    if(mp[x][y]==.)
        return true;

    return false;


bool bfs() 
    queue<node> q;
    q.push(node(sx, 0));

    while(q.size()) 
        node now = q.front(); q.pop();
        if(now.y>=n) 
            return true;
        

    //    printf("(%d,%d) -> ", now.x, now.y);
        
        int nx = now.x, ny = now.y+1;
        if(!check(nx, ny))  continue; // 向右走一步

        for(int i=-1;i<=1;i++)       // 尝试三个方向移动
            nx = now.x + i;
            if(check(nx, ny) && check(nx, ny+1) && check(nx, ny+2) && !vis[nx][ny+2]) 
                q.push(node(nx, ny+2));
                vis[nx][ny+2] = 1;
            
        
    
    return false;



int main() 
    int t; cin>>t;
    while(t--) 
        scanf("%d %d", &n, &k);
        getchar();
        memset(vis, 0, sizeof(vis));
        for(int i=0;i<3;i++) 
            scanf("%s", mp[i]);
            
            if(mp[i][0]==s)
                sx = i;
            
        
        printf("%s\\n", bfs()?"YES":"NO");
    
    
    return 0;
View Code

 

 C - A Mist of Florescence (补)

构造题,技巧就是设计井字形的连通块,把其他颜色块涂到井字的格子上。

技术图片

技术图片
#include<iostream>
#include<cstdio>
using namespace std;

int a, b, c, d;
char ans[50][50];
void solve() 
    for(int i=1;i<=12;i++) 
        for(int j=1;j<50;j++) 
            if(i%2==1 && j%2==1 && a) ans[i][j] = A, --a;
            else ans[i][j] = D;
        
    

    for(int i=13;i<=24;i++) 
        for(int j=1;j<50;j++) 
            if(i%2==1 && j%2==1 && b) ans[i][j] = B, --b;
            else ans[i][j] = D;
        
    

    --c;
    --d;
    for(int i=25;i<=36;i++) 
        for(int j=1;j<50;j++) 
            if(i%2==1 && j%2==1 && c) ans[i][j] = C, --c;
            else ans[i][j] = D;
        
    

    for(int j=1;j<50;j++) 
        ans[37][j] = C;
    

    for(int i=38;i<50;i++) 
        for(int j=1;j<50;j++) 
            if(i%2==1 && j%2==1 && d) ans[i][j] = D, --d;
            else ans[i][j] = C;
        
    



int main() 
    cin>>a>>b>>c>>d;
    solve();
    printf("49 49\\n");
    for(int i=1;i<50;i++) 
        for(int j=1;j<50;j++)
            printf("%c", ans[i][j]);
        printf("\\n");
    
    
    return 0;
View Code

 

E - Igor In the Museum 

DFS到墙的边界 对每块编号!

技术图片
#include<iostream>
#include<cstdio>
using namespace std;

int n, m, k;
char mp[1010][1010];
int v[1010][1010], id;  // v[i][j]: mp[i][j]的分类编号   id: 当前编号
int res[1010*1010];        // res[id]: 第id块的答案

const int dx[] = 0, 0, 1, -1;
const int dy[] = 1, -1, 0, 0;

int ans;
void dfs(int x, int y) 
    if(mp[x][y]==*) 
        ans++;
        return;
    
    v[x][y] = id;
    for(int i=0;i<4;i++) 
        int nx = x+dx[i], ny = y+dy[i];
        if(nx>=0 && nx<m && ny>=0 && ny<n && !v[nx][ny]) 
            dfs(nx, ny);
        
    

int main() 
    scanf("%d %d %d", &m, &n, &k);
    getchar();
    for(int i=0;i<m;i++) 
        scanf("%s", mp[i]);
    

    for(int i=0;i<m;i++) 
        for(int j=0;j<n;j++) 
            if(mp[i][j]==. && !v[i][j]) 
                ++id;
                ans = 0;
                dfs(i, j);
                res[id] = ans;
             
        
    

    while(k--) 
        int x, y;
        scanf("%d %d", &x, &y);
        printf("%d\\n", res[v[x-1][y-1]]);
    

    return 0;
View Code

 

F - The Cild and Toy (补)

贪心!由于每去掉一个点,等价于去掉了所有与它相连的边,就是问去掉全部边的最小代价。答案当然就是每条边两个节点权值小的那头的总和。都不用建图!!

技术图片
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1010;
int n, m;
int w[maxn];

int main() 
    cin>>n>>m;
    for(int i=1;i<=n;i++) 
        scanf("%d", &w[i]);
    
    int u, v, ans = 0;
    for(int i=0;i<m;i++) 
        scanf("%d %d", &u, &v);
        ans += min(w[u], w[v]);
    
    printf("%d\\n", ans);
    
    return 0;
View Code

 

G - New Year Permutation

对连通部分排序就完事了

技术图片
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int n, num[310], id;
int mp[310][310];
bool vis[310];

int ans[310];
struct list 
    vector<int> num;
    vector<int> id;
L[310];

void dfs(int x, int id) 
    vis[x] = 1;

    L[id].num.push_back(num[x]);
    L[id].id.push_back(x);

    for(int i=1;i<=n;i++) 
        if(mp[x][i]) 
            if(!vis[i])
                dfs(i, id);
        
    


int main() 
    cin>>n;
    for(int i=1;i<=n;i++) 
        scanf("%d", &num[i]);
    
    for(int i=1;i<=n;i++) 
        for(int j=1;j<=n;j++) 
            scanf("%1d", &mp[i][j]);
        
    

    for(int i=1;i<=n;i++) 
        if(!vis[i])
            dfs(i, ++id);
    

    for(int i=1;i<=id;i++) 
        // for(int j=0;j<L[i].num.size();j++) 
        //     printf("%d:%d ", L[i].num[j], L[i].id[j]);
        // 
        // cout<<endl;
        
        sort(L[i].num.begin(), L[i].num.end());
        sort(L[i].id.begin(), L[i].id.end());


        for(int j=0;j<L[i].num.size();j++) 
            ans[L[i].id[j]] = L[i].num[j];
        
    
    for(int i=1;i<=n;i++) 
        printf("%d%c", ans[i], i!=n? :\\n);
    
    return 0;
View Code

 

H - Alyona and the Tree (补)

从根开始dfs就好,每个节点为max(0LL, now+w[i])

技术图片
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 100010;
typedef long long ll;

struct Edge 
    int to;
    ll w;
    Edge(int v, ll ww):to(v), w(ww) 
;
vector<Edge> G[maxn];
int n, vw[maxn];
int ans;
void dfs(int u, int fa, ll now) 
    for(int i=0;i<G[u].size();i++) 
        int v = G[u][i].to;
        if(v!=fa) 
            if(vw[v]>=now+G[u][i].w) 
                --ans;
                // printf("%d->%d\\n", u, v);
                dfs(v, u, max(now+G[u][i].w, 0LL));
            
        
    



int main() 
    cin>>n; ans = n;
    for(int i=1;i<=n;i++) 
        scanf("%d", &vw[i]);
    
    int u, w;
    for(int i=2;i<=n;i++) 
        scanf("%d %d", &u, &w);
        G[i].push_back(Edge(u, w));
        G[u].push_back(Edge(i, w));
    

    dfs(1, -1, 0);
    printf("%d\\n", ans-1);
    return 0;
View Code

 

L - Love Triangle 

假的三元环??

技术图片
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 5010;
int n, tot;
int love[maxn], low[maxn];
bool vis[maxn];
bool ans;
void dfs(int u) 
    if(ans) return;

    vis[u] = true;
    low[u] = ++tot;
    int v = love[u];
    if(v && !vis[v]) 
        dfs(v);
        if(love[v] && low[love[v]]==low[u]+2 && love[love[v]]==u) 
            ans = true;
            return;
        
    


int main() 
    cin>>n;
    for(int i=1;i<=n;i++) 
        scanf("%d", &love[i]);
    
    ans = false;
    for(int i=1;i<=n;i++) 
        if(!vis[i] && !ans)
            dfs(i);
    
    printf("%s\\n", ans?"YES":"NO");
    return 0;
View Code

 

N - News Distribution 

并查集

技术图片
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 500100;
int n, m;
int fa[maxn];
int g[maxn], cnt[maxn];

int Find(int x) 
    return fa[x]==x?x:(fa[x]=Find(fa[x]));


void Union(int x, int y) 
    int a = Find(x);
    int b = Find(y);
    if(a==b) return;
    fa[a] = b;


int main() 
    cin>>n>>m;
    for(int i=1;i<=n;i++) fa[i] = i;
    while(m--) 
        int k;
        scanf("%d", &k);
        for(int i=0;i<k;i++) 
            scanf("%d", &g[i]);
        
        for(int i=1;i<k;i++) 
            Union(g[0], g[i]);
        
    
    for(int i=1;i<=n;i++) 
        cnt[Find(i)]++;
    
    for(int i=1;i<=n;i++) 
        printf("%d%c", cnt[Find(i)], i!=n? :\\n);
    
    return 0;
View Code

 

O - NP-Hard Problem (补)

二分图裸题。。。

技术图片
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 100010;
int n, m;
vector<int> G[maxn];
int deg[maxn];
int id[maxn];
vector<int> ans[2];
bool dfs(int u) 
    for(int i=0;i<G[u].size();i++) 
        int v = G[u][i];
        if(!id[v]) 
            id[v] = 3 - id[u];
            if(id[v]==1)
                ans[0].push_back(v);
            else
                ans[1].push_back(v);
            if(!dfs(v)) return false;
         else if(id[v]==id[u]) return false;
    
    return true;


int main() 
    cin>>n>>m;
    int u, v;
    for(int i=0;i<m;i++) 
        scanf("%d %d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
        ++deg[u];
    
    for(int i=1;i<=n;i++) 
        if(!deg[i]) continue;

        if(!id[i]) 
            id[i] = 1;
            ans[0].push_back(i);
            if(!dfs(i)) 
                return 0 * printf("-1\\n");
        


    
    
    for(int k=0;k<=1;k++) 
        printf("%d\\n", ans[k].size());
        for(int i=0;i<ans[k].size();i++) 
            printf("%d%c", ans[k][i], i==ans[k].size()-1?\\n: );
        
    

    return 0;
View Code

 

 

Day2

Day3

Day4

Day5

Day6

 

以上是关于CCPC-Wannafly Summer Camp 2019 全记录的主要内容,如果未能解决你的问题,请参考以下文章

Petrozavodsk Summer Training Camp 2017

蛋糕分发 - summer camp

BZOJ4896 [Thu Summer Camp2016]补退选

bzoj:4105: [Thu Summer Camp 2015]平方运算

Petrozavodsk Summer Training Camp 2017 Day 9

BZOJ 4104 4104: [Thu Summer Camp 2015]解密运算 (智商)