第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)
B : M i n e S w e e p e r I I \mathbf{B:Mine Sweeper II} B:MineSweeperII
题目大意
给你两个大小为 n ∗ m n * m n∗m 的扫雷图 A , B A, B A,B,要求通过最多 n ∗ m 2 \frac{n * m}{2} 2n∗m次转换(转换指 把一个不是雷的格子变成雷, 或者把一个是雷的格子变成空白格),使得 B图的值 和 A图的值相等(值 就是指 扫雷图上的所有数字之和,没有数字或者雷的地方的值为 0 0 0)
分析
一个地雷对周围的影响,等价于把这个地雷改成空白,把周围的空白改成地雷,所以我们只需要求这个图的补图就可以了
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC option("arch=native","tune=native","no-zero-upper")
#pragma GCC target("avx2")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 1e3 + 10;
char a[N][N];
char b[N][N];
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
scanf("%s",a[i] + 1);
for(int i = 1;i <= n;i++)
scanf("%s",b[i] + 1);
int ans = 0;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
if(a[i][j] != b[i][j]) ans++;
if(ans <= n * m / 2){
for(int i = 1;i <= n;i++)
printf("%s\n",a[i] + 1);
}
else{
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++)
if(a[i][j] == '.') printf("X");
else printf(".");
puts("");
}
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
C : S u m o f L o g \mathbf{C:Sum of Log} C:SumofLog
题目大意
给定 x , y x,y x,y,我们需要把
给算出来
分析
这个问题可以转换成,一个范围内,当 i & j = = 0 i \& j == 0 i&j==0 的的情况下,二进制最高位的所有数的和,所以我们可以想到数位DP的做法
我们可以分两种情况来讨论,一种情况是当 i > j i > j i>j 的情况,这个时候 log 2 ( i + j ) \log_2(i + j) log2(i+j)的值就是 i i i的二进制表示下最高位的位置,反过来再讨论 i < j i < j i<j 的情况即可
代码
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 50;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
int gcd(int a,int b){return (b>0)?gcd(b,a%b):a;}
ll f[N][2][2];
ll x,y;
int a[N],b[N];
ll dfs(int pos,bool sta,bool stb){
if(!pos) return 1;
if(f[pos][sta][stb] != -1) return f[pos][sta][stb];
int ed1 = sta ? a[pos] : 1;
int ed2 = stb ? b[pos] : 1;
ll res = 0;
for(int i = 0;i <= ed1;i++)
for(int j = 0;j <= ed2;j++){
if(j & i) continue;
res = (res + dfs(pos - 1,sta && i == ed1,stb && j == ed2));
}
f[pos][sta][stb] = res;
return res;
}
ll run(){
int la = 0,lb = 0;
memset(a,0,sizeof a);
memset(b,0,sizeof b);
while(x) {
a[++la] = x & 1;
x >>= 1;
}
while(y){
b[++lb] = y & 1;
y >>= 1;
}
ll res = 0;
memset(f,-1,sizeof f);
for(int i = la;i;i--){
res = (res + dfs(i - 1,i == la,i > lb) * i) % mod;
}
memset(f,-1,sizeof f);
for(int i = lb;i;i--){
res = (res + dfs(i - 1,i > la,i == lb) * i) % mod;
}
return res;
}
int main(){
int T;
read(T);
while(T--){
read(x),read(y);
dl(run());
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
D : W a l k e r \mathbf{D:Walker} D:Walker
题目大意
给你两个人的位置和速度,以及这段路程的总长度,问你最少多长时间两个人可以走完这整段路程
分析
分情况讨论即可
1. 1. 1.第一个人独自走完全程
2. 2. 2.第二个人独自走完全程
3. 3. 3.右边的人向左走左边的人向右走
4. 4. 4.最终在中间相遇,二分位置
代码
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
const ll mod= 1000000007;
const double eps = 1e-10;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
int gcd(int a,int b){return (b>0)?gcd(b,a%b):a;}
double v1,v2,p1,p2,n;
double res4;
int sgn(double x)
{
if(fabs(x)<=eps)
return 0;
else if(x<0)
return -1;
else
return 1;
}
bool check(double mid){
double t1 = (min(mid - p1,p1) + mid)/ v1;
double t2 = (min(p2 - mid,n - p2) + n - mid) / v2;
res4 = min(res4,max(t1,t2));
return sgn(t1 - t2) < 0;
}
int main(){
int T;
read(T);
while(T--){
cin >> n >> p1 >> v1 >> p2 >> v2;
if(p1 > p2) swap(p1,p2),swap(v1,v2);
double res1 = (min(n - p1,p1) + n) / v1;
double res2 = (min(n - p2,p2) + n) / v2;
double res3 = max((n - p1) / v1,p2 / v2);
res4 = 1e9;
double l = p1,r = p2;
for(int i = 1;i <= 1000;i++){
double mid = (l + r) / 2;
if(check(mid)) l = mid;
else r = mid;
}
printf("%.10lf\n",min(min(res1,res2),min(res3,res4)));
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
G : F i b o n a c c i \mathbf{G:Fibonacci} G:Fibonacci
题目大意
将当前斐波那契数分别与其后到 n n n的数相乘,值为偶数总和加一。
分析
签到题,找一下规律就可以了
代码
#include <iostream>
using namespace std;
typedef long long ll;
int main(){
ll sum = 0;
ll n;
scanf("%lld",&n);
sum = n / 3 * (n - 1) - (n / 3) * (n / 3 - 1) / 2;
printf("%lld",sum);
}
M : G i t i g n o r e \mathbf{M:Gitignore} M:Gitignore
题目大意
给你一些文件夹和文件,文件夹没有空的,文件夹里面可能有文件和文件夹,有些文件是可以忽略的,有些文件是不能被忽略的,我们要找到最少的能被忽略的文件的个数。
分析
几个月后再看这道题发现,小丑竟是我自己
当时没学 a c ac ac自动机,可持久化 t r i e trie trie也是直接跳过直接学的主席树,导致差点都忘了字典树这个数据结构,最后用一种很复杂的存图方式把这棵树存下来,然后 d f s dfs dfs一下就可以了
来欣赏一下小丑的代码
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
map<string,int> M;
int h[N],ne[N],e[N],idx;
int ppp[N][N];
int sum[N];
int son[N];
bool st[N];
int ans;
int num;
string str;
int n,m;
int find(string str){
if(!M[str]) M[str] = ++num;
return M[str];
}
void add(int x,int y){
ne[idx] = h[x],e[idx] = y,h[x] = idx++;
}
void init(){
memset(h,-1,sizeof h);
memset(ppp,0,sizeof ppp);
memset(sum,0,sizeof sum);
memset(son,0,sizeof son);
memset(st,0,sizeof st);
M.clear();
idx = 0,num = 0;
ans = 0;
scanf("%d%d",&n,&m);
}
void dfs(int u){
if(h[u] == -1) son[u] = 1;
for(int i = h[u];~i;i = ne[i]){
int j = e[i];
dfs(j);
son[u] += son[j];
sum[u] += sum[j];
}
}
void qqqq(int u){
// cout <<u << endl << ' ' <<son[u] << ' ' << sum[u] << endl;
if(son[u] == sum[u]){
// cout <<u << endl;
// cout <<son[u] << ' ' << sum[u] << endl;
ans++;
return ;
}
for(int i = h[u];~i;i = ne[i]){
int j = e[i];
qqqq(j);
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
init();
int res = 0;
for(int i = 1;i <= n;i++){
cin >> str;
string back = "";
int last = 0;
for(int j = 0;j < str.length();j++){
if(str[j] == '/'){
int xx = find(back);
if(!ppp[last][xx]){
ppp[last][xx] = ++res;
add(last,ppp[last][xx]);
}
// cout <<last <<' ' <<ppp[last][xx] << endl;
last = ppp[last][xx];
back = "";
}
else{
back = back + str[j];
}
}
int xx = find(back);
if(!ppp[last][xx]){
ppp[last][xx] = ++res;
add(last,ppp[last][xx]);
}
// cout <<last <<' ' <<ppp[last][xx] << endl;
sum[ppp[last][xx]] = 1;
back = "";
}
for(int i = 1;i <= m;i++){
cin >> str;
string back = "";
int last = 0;
for(int j = 0;j < str.length();j++){
if(str[j] == '/'){
int xx = find(back);
if(!ppp[last][xx]){
ppp[last][xx] = ++res;
add(last,ppp[last][xx]);
}
// cout <<last <<' ' <<ppp[last][xx] << endl;
last = ppp[last][xx];
back = "";
}
else{
back = back + str[j];
}
}
int xx = find(back);
if(!ppp[last][xx]){
ppp[last][xx] = ++res;
add(last,ppp[last][xx]);
}
// cout <<last <<' ' <<ppp[last][xx] << endl;
back = "";
}
dfs(0);
for(int i = h[0];~i;i = ne[i]){
int j = e[i];
if(st[j]) continue;
st[j] = true;
qqqq(j);
}
printf("%d\n",ans);
}
}