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;
}