AtCoder Beginner Contest 289

A - flip

#include <bits/stdc++.h>

using namespace std;

int32_t main() {
    ios::sync_with_stdio(false) , cin.tie(nullptr) , cout.tie(nullptr);
    string s;
    cin >> s;
    for( auto i : s )
        cout << ( i == '1' ? '0' : '1' );
    return 0;
}

B - V

题目比较难懂,简单来说就是"レ"连起来的部分整体反转,输入说是读入\(a_i\)\(a_i\)后有一个"レ"

#include <bits/stdc++.h>

using namespace std;

int main(){
    ios::sync_with_stdio(false) , cin.tie(nullptr) , cout.tie(nullptr);
    int n , m;
    cin >> n >> m;
    vector<int> a(m);
    for( auto & it : a ) cin >> it;
    vector<int> res , t ;
    for( int i = 1 , j = 0 ; i <= n ; i ++ ){
        if( j < a.size() && i == a[j] ){
            t.push_back(i) , j ++;
        }else if( !t.empty() && i == t.back()+1 ){
            t.push_back(i) , reverse( t.begin() , t.end() );
            for( auto it : t ) res.push_back(it);
            t.clear();
        }else res.push_back(i);
    }
    for( auto it : res )
        cout << it << " ";
    return 0;
}

C - Coverage

给一些集合,问拼出全集的方案数。数据范围很小,所以我用搜索直接把答案搜出来。

#include <bits/stdc++.h>

using namespace std;

int n , m , res;
vector<vector<int>> p;

void dfs( int i , vector<int> t ){

    if( i == m ){
        if( t == vector<int>(n,1) ) res ++;
        return ;
    }
    dfs( i+1 , t );
    for( auto it : p[i] ) t[it-1] = 1;
    dfs( i+1 , t );
    return;
}

int32_t main() {
    ios::sync_with_stdio(false) , cin.tie(nullptr) , cout.tie(nullptr);
    cin >> n >> m;
    p.resize(m);
    for( auto & it : p ){
        int c; cin >> c;
        it = vector<int>(c);
        for( auto &i : it ) cin >> i;
    }
    dfs( 0 , vector<int>(n) );
    cout << res << "\n";
    return 0;
}

D - Step Up Robot

数很少,直接dfs枚举每个数选不选

# include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 1e5+5;
bitset<N> vis;
vector<int> a;
int X;

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
    return x * f;
}

void dfs( int x ){
    if( x == X ){
        cout << "Yes\n";
        exit(0);
    }
    for( auto i : a ){
        if( i + x > X ) break;
        if( vis[ i+x ] ) continue;
        vis[i+x] = 1 , dfs( i+x );
    }
    return;
}

int32_t main() {
    int n = read();
    a = vector<int>(n);
    for( int & i : a ) i = read();
    for( int m = read() , x ; m ; m -- ) x = read() , vis[x] = 1;
    X = read();
    dfs(0);
    cout << "No\n";
    return 0;
}

E - Swap Places

有一个图,保证联通,图上的点有黑白两种颜色,一开始有两个人,一个人在1另一个人在n,两个人每次都可以走一步,但是两个人不能同时在颜色相同的点上,问两个人是否能同时走到对方的起始位置,且输出最短步数。

我想到的方式是直接bfs的方式搜索出答案,然后我用pair<int,int>表示两个人的位置,因此我使用map<pii,int> dis来表示最短距离

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0 , ch = getchar();
    while ( ch < '0' || ch > '9' ) ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

#define mp make_pair
typedef pair<int,int> pii;

void solve(){
    int n = read() , m = read() , res = -1;
    vector<int> col(n+1);
    for( int i = 1 ; i <= n ; i ++ ) col[i] = read();
    vector<vector<int>>e(n+1,vector<int>());
    for( int u , v ; m ; m -- )
        u = read() , v = read() , e[u].push_back(v) , e[v].push_back(u);
    queue<pii> q;
    set<pii> vis;
    map<pii,int> dis;
    q.emplace( 1 , n ) , dis[ mp(1,n) ] = 0;
    while( !q.empty() ){
        auto [ a , b] = q.front() ; q.pop();
        if( vis.emplace( a , b ).second == false ) continue;
        if( a == n && b == 1 ){
            res = dis[ mp(a,b) ];
            break;
        }
        for( auto da : e[a] )
            for( auto db : e[b] ){
                if( col[da] == col[db] ) continue;
                if( vis.count( mp( da , db ) ) ) continue;
                if( dis.count( mp( da , db ) ) && dis[ mp( da , db ) ] <= dis[ mp(a,b) ] + 1 ) continue;
                dis[ mp(da,db) ] = dis[ mp(a,b) ] + 1 , q.emplace( da , db );
            }
    }
    printf("%d\n" , res );
}

int32_t main() {
    for( int T = read() ;  T ; T -- )
        solve();
    return 0;
}

结果TLE16,然后我想到了我不需要dis内部有序,所以可以用unordered_map优化

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0 , ch = getchar();
    while ( ch < '0' || ch > '9' ) ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

#define mp make_pair
typedef pair<int,int> pii;
const int base = 10000;

#define H(x,y) (x*base+y)

void solve(){
    int n = read() , m = read() , res = -1 ;
    vector<int> col(n+1);
    for( int i = 1 ; i <= n ; i ++ ) col[i] = read();
    vector<vector<int>>e(n+1,vector<int>());
    for( int u , v ; m ; m -- )
        u = read() , v = read() , e[u].push_back(v) , e[v].push_back(u);
    queue< int > q;
    set< int > vis;
    unordered_map< int ,int> dis;
    q.emplace( H(1,n) ) , dis[ q.front() ] = 0;
    for( int a , b , p , d ; !q.empty() ; ){
        p = q.front() , a = p / base , b = p % base , q.pop() ;
        if( vis.emplace( p ).second == false ) continue;
        if( a == n && b == 1 ){
            res = dis[p];
            break;
        }
        for( auto da : e[a] )
            for( auto db : e[b] ){
                if( col[da] == col[db] ) continue;
                d = H(da,db);
                if( vis.count( d ) ) continue;
                if( dis.count(d) && dis[ d ] <= dis[ p ] + 1 ) continue;
                dis[ d ] = dis[ p ] + 1 , q.emplace( d );
            }
    }
    printf("%d\n" , res );
}

int32_t main() {
    for( int T = read() ;  T ; T -- )
        solve();
    return 0;
}

然后TLE1只差一点点就可以过了,我想到unordered_map本质上是哈希,但是pair的哈希比较慢,并且\(N\le 2000\),所以想到了压位,用一个int直接表示,#define H(x,y) (x*base+y)

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0 , ch = getchar();
    while ( ch < '0' || ch > '9' ) ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

//#define mp make_pair
//typedef pair<int,int> pii;
const int base = 10000;

#define H(x,y) (x*base+y)

void solve(){
    int n = read() , m = read() , res = -1 ;
    vector<int> col(n+1);
    for( int i = 1 ; i <= n ; i ++ ) col[i] = read();
    vector<vector<int>>e(n+1,vector<int>());
    for( int u , v ; m ; m -- )
        u = read() , v = read() , e[u].push_back(v) , e[v].push_back(u);
    queue< int > q;
    unordered_set< int > vis;
    unordered_map< int ,int> dis;
    q.emplace( H(1,n) ) , dis[ q.front() ] = 0;
    for( int a , b , p , d ; !q.empty() ; ){
        p = q.front() , a = p / base , b = p % base , q.pop() ;
        if( vis.emplace( p ).second == false ) continue;
        if( a == n && b == 1 ){
            res = dis[p];
            break;
        }
        for( auto da : e[a] )
            for( auto db : e[b] ){
                if( col[da] == col[db] ) continue;
                d = H(da,db);
                if( vis.count( d ) ) continue;
                if( dis.count(d) && dis[ d ] <= dis[ p ] + 1 ) continue;
                dis[ d ] = dis[ p ] + 1 , q.emplace( d );
            }
    }
    printf("%d\n" , res );
}

int32_t main() {
    for( int T = read() ;  T ; T -- )
        solve();
    return 0;
}

于是有了这样的代码,虽然快了一点,但还是TLE1,然后我想到,如果一开始两点颜色一样的一定不可以,于是加了如下的剪枝

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0 , ch = getchar();
    while ( ch < '0' || ch > '9' ) ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

const int base = 10000;

#define H(x,y) (x*base+y)
int n , m , res;


int32_t main() {
    for( int T = read() ;  T ; T -- ){
            int n = read() , m = read() , res = -1 ;
        vector<int> col(n+1);
        for( int i = 1 ; i <= n ; i ++ ) col[i] = read();
        vector<vector<int>>e(n+1,vector<int>());
        for( int u , v ; m ; m -- )
        u = read() , v = read() , e[u].push_back(v) , e[v].push_back(u);
        if( col[1] == col[n] ){
            printf("-1\n");
            continue;
        }
        queue< int > q;
        unordered_set< int > vis;
        unordered_map< int ,int> dis;
        q.emplace( H(1,n) ) , dis[ q.front() ] = 0;
        for( int a , b , p , d ; !q.empty() ; ){
            p = q.front() , a = p / base , b = p % base , q.pop() ;
            if( vis.emplace( p ).second == false ) continue;
            if( a == n && b == 1 ){
                res = dis[p];
                break;
            }
            for( auto da : e[a] )
                for( auto db : e[b] ){
                    if( col[da] == col[db] ) continue;
                    d = H(da,db);
                    if( vis.count( d ) ) continue;
                    if( dis.count(d) && dis[ d ] <= dis[ p ] + 1 ) continue;
                    dis[ d ] = dis[ p ] + 1 , q.emplace( d );
                }
        }
        printf("%d\n" , res );
    }
    return 0;
}

总算是卡过去了,最后半分钟a题也太刺激了吧。但是赛后看Jiangly的录像发现,可以直接用二维数组通过,于是重新写了下面的代码

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0 , ch = getchar();
    while ( ch < '0' || ch > '9' ) ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

int n , m , res;

void solve(){
	int n = read() , m = read();
	vector<int> col(n);
	vector<vector<int> > e(n) , dis( n, vector<int>(n,INT_MAX) ) , vis( n, vector<int>(n,0) );
	for( auto & i : col ) i = read();
	for( int u , v ; m ; m -- )
		u = read()-1 , v = read()-1 , e[u].push_back(v) , e[v].push_back(u);
	if( col[0] == col[n-1] ) return printf("-1\n") , void();
	queue< pair<int,int> > q;
	q.emplace( 0 , n-1 ) , dis[0][n-1] = 0;
	while( !q.empty() ){
		auto [ u , v ] = q.front() ; q.pop();
		if( vis[u][v] ) continue;
		vis[u][v] = 1;
		if( u == n-1 && v == 0 ) break;
		for( auto du : e[u] )
			for( auto dv : e[v] ){
				if( col[du] == col[dv] ) continue;
				if( dis[du][dv] <= dis[u][v] + 1 ) continue;
				dis[du][dv] = dis[u][v] + 1 , q.emplace( du , dv );
			}
	}
	if( dis[n-1][0] == INT_MAX ) printf("-1\n");
	else printf("%d\n" , dis[n-1][0] );
	return;
}

int32_t main() {
	for( int T = read() ; T ; T -- ) solve();
    return 0;
}

结果就是跑的飞快

F - Teleporter Takahashi(补题)

题目意思就是让在矩形R,选择一个点,然后对称过去,至多进行\(10^6\)次,是否可以到达终点。

先单独考虑x的情况,\(x_0\)关于\(a\)对称得到\(x_1=2a-x\),然后在关于\(a+1\)对称得到\(x_2=2(a+1)-x_1=x_0+2\)。这样的话每次移动两步就好,y同理。所以始末位置一定要奇偶性相同,然后特判矩形类的点只有一行或一列的情况下,x或y只能移动一步,看一步能不能到目标点即可

#include <bits/stdc++.h>
using namespace std;

#define int long long

int32_t main(){
	int sx , sy , ex , ey , a , b , c , d ;
	cin >> sx >> sy >> ex >> ey >> a >> b >> c >> d;
	if( (sx&1)!=(ex&1) || (sy&1)!=(ey&1) ){
		printf("No\n");
		return 0;
	}
	if( ( a == b && sx != ex ) || ( c == d && sy != ey ) ){
		sx = 2*a - sx , sy = 2*c - sy;
		if( ( a == b && sx != ex ) || ( c == d && sy != ey ) ){
			printf("No\n");
			return 0;
		}
		printf("Yes\n%lld %lld\n" , a , c );
	}else printf("Yes\n");
	while( sx < ex ) printf("%lld %lld\n%lld %lld\n" , a , c , a+1 , c ) , sx += 2;
	while( sx > ex ) printf("%lld %lld\n%lld %lld\n" , a+1 , c , a , c ) , sx -= 2;
	while( sy < ey ) printf("%lld %lld\n%lld %lld\n" , a , c , a , c+1 ) , sy += 2;
	while( sy > ey ) printf("%lld %lld\n%lld %lld\n" , a , c+1 , a , c ) , sy -= 2;
	return 0;
}
posted @ 2023-02-14 23:23  PHarr  阅读(29)  评论(0编辑  收藏  举报