AtCoder Beginner Contest 302(A-F)

A

思路:如果能整除就直接输出a/b,否则就需要再攻击一下才能打到0

#include 
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
#define int LL
typedef pair<int, int> PII;

void solve()
{
    int a, b;
    cin >> a >> b;
    if(a%b==0){
        cout << a / b << endl;
    }else{
        cout << a/b+1 << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t -- ) solve(); 
    system("pause");    
    return 0;
}

B

思路:深搜题。要保证snuke在一条线上,那方向不能改变,每找到一个s从它八个方向都看一下可不可以,当我path路径上放满五个PII的时候,就说明找到了答案,直接打印。

#include 
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
#define int LL
typedef pair<int, int> PII;
const int N = 110;
int dx[8] = {0,-1,0,1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
char a[N][N];
int h, w;
PII path[6];
string str="snuke";

void dfs(int x, int y, int f,int cnt)//f为方向,方向每次不能改变
{
    path[cnt] = {x, y};
    if(cnt == 4){
        for(int  i = 0; i < 5; i ++ ){
            cout << path[i].first << ' ' << path[i].second << endl;
        }
        return;
    }
    int xx = x + dx[f], yy = y + dy[f];
    if(xx<1||yy<1||xx>h||yy>w) return;
    if(str[cnt+1] == a[xx][yy]){
        dfs(xx,yy,f,cnt+1);
    } 
}

void solve()
{
    cin >> h >> w;
    for(int i = 1; i <= h; i ++ ){
        for(int j = 1; j <= w; j ++ ){
            cin >> a[i][j];
        }
    } 
    for(int i = 1; i <= h; i ++ ){
        for(int j = 1; j <= w; j ++ ){
            if(a[i][j] == 's'){//第一个字母是s就搜
                for(int k = 0; k < 8; k ++ ){
                    int x = i + dx[k],y=j+dy[k];
                    if(x<1||y<1||x>h||y>w){
                        continue;
                    }
                    dfs(i,j,k,0);
                }
            }
        }
    }   
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t -- ) solve(); 
    system("pause");    
    return 0;
}

C

思路:还是深搜题,看这个n,m那么少,那么一定最暴力的算法就可以了。用字符串数组存,从1到n遍历,如果一个字符串没有用过并且符合条件(与当前字符串有且仅有一个字母不同),那就以这个新的字符串为起始点,标记用过,继续搜。

#include 
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
#define int LL
typedef pair<int, int> PII;
const int N = 10;
string s[N];
bool st[N];
int n, m;
int flag;

bool check(string a, string b){
    int cnt = 0;
    for(int i = 0; i < m; i ++ ){
        if(a[i] != b[i]){
            cnt ++;
            if(cnt > 1) return false;
        }
    }
    if(cnt == 1) return true;
    return false;
}

void dfs(int x,int cnt)//当前枚举的哪个字符串,枚举几个了
{
    if(cnt == n - 1){
        cout << "Yes" << endl;
        flag = 1;
        return;
    }
    for(int i = 0; i < n; i ++ ){
        if(check(s[i],s[x]) && !st[i]){
            st[i] = 1;
            dfs(x+1,cnt+1);
            st[i] = 0;
        }
        if(flag) return;
    }
}

void solve()
{
    cin >> n >> m;
    for(int i = 0; i < n; i ++ )
        cin >> s[i];
    sort(s,s+n);
    for(int i = 0; i < n; i ++ ){
        memset(st, 0,sizeof st);
        st[i] = 1;
        dfs(i,0);
        if(flag) break;
    }
    if(!flag) cout << "No" << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t -- ) solve(); 
    system("pause");    
    return 0;
}

D

思路:非常典型的二分题。由于我基本功不扎实调了半天 排一遍b数组,对于a里的每个数我都二分去b里面找符合条件(abs(b[mid]-x)<=d)的最大值,然后对于每个ai找到的结果取max

#include 
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
#define int LL
typedef pair<int, int> PII;
const int N = 200010;
int a[N], b[N];
int n, m, d;
int res = -1;

void solve()
{
    cin >> n >> m >> d;
    int l, r, mid;
    for(int i = 0; i < n; i ++ ) cin >> a[i];
    for(int i = 0; i < m; i ++ ) cin >> b[i];
    sort(b, b + m);
    for(int i = 0; i < n; i ++ ){
    	//abs(x-b[mid])<=d有两种可能
    	//x大或者小,一起写的话不太好分,我就分成两种情况了
        int x = a[i];
        l = 0, r = m - 1;
        //先假设a大于b
        while(l < r){
            mid = l + r >> 1;
            if(x - b[mid] <= d){
                r = mid;
            }else l = mid + 1;
        }
        if(abs(x - b[l]) <= d){
            res = max(res, x + b[l]);
        }
        l = 0, r = m - 1;
       	//然后假设b大于a的情况
        while(l < r){
            mid = l + r + 1 >> 1;
            if(b[mid] - x <= d){
                l = mid;
            }else r = mid - 1;
        }
        if(abs(b[l] - x) <= d){
            res = max(res, x + b[l]);
        }
    }
    cout << res << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t -- ) solve(); 
    system("pause");    
    return 0;
}

E

都不难的,能出,都怪我前面调得太慢了比赛的时候没能出这道题
思路:这显然不能用个图去存,只需要维护当前有哪些点没有边相连。开个集合数组,s[i]存的i当前与i点邻接的点(题干说保证没有重边,那开vector也行,但是我觉得set的erase用着更简单)

#include 
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
#define int LL
typedef pair<int, int> PII;
const int N = 300010;
unordered_set<int> s[N];
int n, q;

void solve()
{
    cin >> n >> q;
    int cnt = n;
    while(q -- ){
        int op;
        cin >> op;
        if(op&1){
            int a, b;
            cin >> a >> b;
            //如果开始这个点没有边相连,加了边就要让cnt--
            //如果本来这条边就有边相连,那再加一条边cnt不变
            cnt -= s[a].size() == 0;
            cnt -= s[b].size() == 0;
            s[a].insert(b);
            s[b].insert(a);
        }else{
            int u;
            cin >> u;
            //先把与u相连的点里删掉u
            //如果删完u这个点就没有边连了,那cnt++
            for(auto i : s[u]){
                s[i].erase(u);
                cnt += s[i].size() == 0;
            }
            //再把u的所有点集删掉
            cnt += s[u].size() != 0;
            s[u].clear();
        }
        cout << cnt << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t -- ) solve(); 
    system("pause");    
    return 0;
}

F

思路:有相同元素的两个集合可以才可以合并,可以抽象成图,a连着b,c连着b,那么a和c也可以相通,之后如果不能让所有点连通的,就是-1,能的话是最短路/2

#include 
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
#define int LL
typedef pair<int, int> PII;
const int N = 200010;
int n, m;
int dis[N*2];
queue<int> q;

void solve()
{
    cin >> n >> m;
    vector<vector<int>> g(n + m);
    for(int i = 0; i < n; i ++ ){
        int k;
        cin >> k;
        while(k -- ){
            int a;
            cin >> a;
            a -- ;
            //m+i里m相当于偏移量,等同于i里面存了这个点,这个点的值里面也存了有i
            g[a].push_back(m + i);
            g[m + i].push_back(a);
        }
    }
    memset(dis, -1, sizeof dis);
    dis[0] = 0;
    q.push(0);
    while(q.size()){
        int x = q.front();
        q.pop();
        //遍历每一个跟x相邻的点
        //如果某个跟x相邻的点还不可达(dis[i]==-1),那么更新它的距离为dis[x]+1
        for(auto i : g[x]){
            if(dis[i] == -1){
                dis[i] = dis[x] + 1;
                q.push(i);//之后再把这个新扩进来的点加入集合
            }
        }
    }
    cout << dis[m - 1] / 2 - 1 << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t -- ) solve(); 
    system("pause");    
    return 0;
}

你可能感兴趣的:(深度优先,算法)