The 2018 ACM-ICPC Asia Beijing First Round Online Contest
A - Saving Tang Monk II
题意:
给出一个地图
S起点 T终点 #毒气 B氧气 P药片 .空地
每次可以向上下左右4个方向移动,花费时间为1
#毒气室,需要一个氧气瓶,并且需要额外花费时间1休息
B氧气室,有无数个氧气瓶,每进入一次可获得一个氧气瓶
P加速药片,下次移动不花费时间
最多只能带5个氧气瓶
题解:
宽搜,维护到(x,y)位置带z个氧气的最小时间
#include <bits/stdc++.h>
#define FOR(I,S,T) for(int I=(S);I<=(T);I++)
//#define mp make_pair
#define pb push_back
#define eb emplace_back
#define endl '\n'
using namespace std;
typedef long long ll;
const int maxn = 1e2 + 2;
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f3f3f3f3f;
int dis[maxn][maxn][10];
char mp[maxn][maxn];
struct node{
int x, y, o, dis;
node(){x = y = o = dis = 0;}
node(int a, int b, int c, int d){
x = a; y = b; o= c; dis = d;
}
};
int sx, sy, ex, ey, Ans;
queue<node> que;
int dir[4][2] = {{1,0},{-1,0},{0,-1},{0,1}};
int n , m;
int main() {
while (~scanf("%d%d", &n, &m)){
if (n == 0 && m == 0) break;
getchar();
memset(dis, inf, sizeof(dis));
while (que.size()) que.pop();
FOR(i,0,n-1) {
FOR(j,0,m-1) {
mp[i][j] = getchar();
if (mp[i][j] == 'S') sx = i, sy = j;
else if (mp[i][j] == 'T') ex = i, ey = j;
}
getchar();
}
dis[sx][sy][0] = 0;
que.push(node(sx,sy,0,0));
while (que.size()){
node u = que.front();
int x = u.x, y = u.y;
que.pop();
FOR(i,0,3){
int nx = u.x + dir[i][0], ny = u.y + dir[i][1];
if (nx < 0 || nx >= n) continue;
if (ny < 0 || ny >= m) continue;
if (mp[x][y] == '.' || mp[x][y] == 'S'){
FOR(j,0,5){
if (dis[x][y][j] + 1 < dis[nx][ny][j]){
dis[nx][ny][j] = dis[x][y][j] + 1;
que.push(node(nx,ny,j,dis[nx][ny][j]));
}
}
}
else if (mp[x][y] == '#'){
FOR(j,0,4){
if (dis[x][y][j+1] + 2 < dis[nx][ny][j]){
dis[nx][ny][j] = dis[x][y][j+1] + 2;
que.push(node(nx, ny, j, dis[nx][ny][j]));
}
}
}
else if (mp[x][y] == 'B'){
FOR(j,1,5){
if (dis[x][y][j-1] + 1 < dis[nx][ny][j]){
dis[nx][ny][j] = dis[x][y][j-1] + 1;
que.push(node(nx,ny,j,dis[nx][ny][j]));
}
}
}
else if (mp[x][y] == 'P'){
FOR(j,0,5){
if (dis[x][y][j] < dis[nx][ny][j]){
dis[nx][ny][j] = dis[x][y][j];
que.push(node(nx,ny,j,dis[nx][ny][j]));
}
}
}
}
Ans = inf;
}
FOR(i,0,5){
if (dis[ex][ey][i] < Ans){
Ans = dis[ex][ey][i];
}
}
if (Ans == inf) printf("-1\n");
else printf("%d\n", Ans) ;
}
return 0;
}
B - Tomb Raider
题意:
给n个串,求这n个串的最长公共子串
题解: 二进制分解
分解出一个串的所有子串,然后枚举第一串的子串,暴力判断在其他串中是否出现过
#include <bits/stdc++.h>
#define FOR(I,S,T) for(int I=(S);I<=(T);I++)
#define pb push_back
#define mp male_pair
#define fi first
#define se second
#define endl '\n'
using namespace std;
set<string> s[20];
vector <string> ans;
int n;
int main() {
while(~scanf("%d", &n)){
string st;
ans.clear();
FOR(i,0,n)s[i].clear();
FOR(t,0,n-1){
cin >> st;
string tmp = "";
int len = st.size();
FOR(i,1,(1<<len)-1){
int x = i;
tmp = "";
FOR(j,0,len-1){
if (x & (1<<j)){
tmp.insert(tmp.end(), 1,st[j]);
}
}
string tmp2 = "";
FOR(j,1,tmp.size()-1){
tmp2 = tmp.substr(j);
string tmp3 = tmp.substr(0,j);
tmp2.insert(tmp2.end(), tmp3.begin(), tmp3.end());
s[t].insert(tmp2);
}
s[t].insert(tmp);
}
}
for (auto i : s[0]){
int flag = 1;
FOR(j,1,n-1){
if (s[j].count(i) == 0){
flag = 0;
break;
}
}
if (flag) ans.pb(i);
}
sort(ans.begin(), ans.end());
string Ans = "";
for (auto i : ans){
if(i.size() > Ans.size()) Ans = i;
}
if (Ans == "") cout << "0" << endl;
else cout << Ans << endl;
}
return 0;
}
C - Cheat
题意:给出”吹牛皮“的打牌规则和4个人的出牌策略
题解:
大模拟,按照题解写就行
学弟写的代码;
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int poke[5][14];
int hand[5];
int table[14];
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0), cout.tie(0);
char ch;
while (cin >> ch)
{
memset(poke, 0, sizeof(poke));
memset(table, 0, sizeof(table));
if (ch == 'A')
poke[1][1]++;
else if ('2' <= ch && ch <= '9')
poke[1][ch - '0']++;
else if (ch == '1')
{
cin >> ch;
poke[1][10]++;
}
else if (ch == 'J')
poke[1][11]++;
else if (ch == 'Q')
poke[1][12]++;
else if (ch == 'K')
poke[1][13]++;
for (int i = 1; i <= 4; i++)
for (int j = 1; j <= 13; j++)
{
if (i == 1 && j == 1)
continue;
cin >> ch;
if (ch == 'A')
poke[i][1]++;
else if ('2' <= ch && ch <= '9')
poke[i][ch - '0']++;
else if (ch == '1')
{
cin >> ch;
poke[i][10]++;
}
else if (ch == 'J')
poke[i][11]++;
else if (ch == 'Q')
poke[i][12]++;
else if (ch == 'K')
poke[i][13]++;
}
hand[1] = hand[2] = hand[3] = hand[4] = 13;
int rndpoke = 0;
int rndplayer = 0;
while (hand[1] && hand[2] && hand[3] && hand[4])
{
rndpoke++;
rndpoke = (rndpoke - 1) % 13 + 1;
rndplayer++;
rndplayer = (rndplayer - 1) % 4 + 1;
if (rndplayer == 1)
{
if (poke[1][rndpoke])
{
poke[1][rndpoke]--;
hand[1]--;
table[rndpoke]++;
int nextrndpoke = rndpoke + 1;
nextrndpoke = (nextrndpoke - 1) % 13 + 1;
if (poke[2][nextrndpoke] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[2][i] += table[i];
hand[2] += table[i];
table[i] = 0;
}
}
else if (poke[3][rndpoke] == 4)
{
for (int i = 1; i <= 13; i++)
{
poke[3][i] += table[i];
hand[3] += table[i];
table[i] = 0;
}
}
else if (hand[1] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[4][i] += table[i];
hand[4] += table[i];
table[i] = 0;
}
}
}
else
{
int curpoke = -1;
if (poke[1][10])
curpoke = 10;
if (curpoke == -1)
{
for(int i=2;i<=9;i++)
if (poke[1][i])
{
curpoke = i;
break;
}
}
if (curpoke == -1)
{
if (poke[1][1])
curpoke = 1;
else if (poke[1][11])
curpoke = 11;
else if (poke[1][13])
curpoke = 13;
else
curpoke = 12;
}
poke[1][curpoke]--;
hand[1]--;
table[curpoke]++;
int nextrndpoke = rndpoke + 1;
nextrndpoke = (nextrndpoke - 1) % 13 + 1;
if (poke[2][nextrndpoke] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
else if (poke[3][rndpoke] == 4)
{
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
else if (hand[1] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
}
}
else if(rndplayer==2)
{
if (poke[2][rndpoke])
{
int num = poke[2][rndpoke];
hand[2] -= num;
poke[2][rndpoke] = 0;
table[rndpoke] += num;
if (poke[3][rndpoke] == 4)
{
for (int i = 1; i <= 13; i++)
{
poke[3][i] += table[i];
hand[3] += table[i];
table[i] = 0;
}
}
else if (hand[2] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[4][i] += table[i];
hand[4] += table[i];
table[i] = 0;
}
}
else if (num + poke[1][rndpoke] > 4)
{
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
}
else
{
int curpoke = -1;
if (poke[2][10])
curpoke = 10;
if (curpoke == -1)
{
for (int i = 2; i <= 9; i++)
if (poke[2][i])
{
curpoke = i;
break;
}
}
if (curpoke == -1)
{
if (poke[2][1])
curpoke = 1;
else if (poke[2][11])
curpoke = 11;
else if (poke[2][13])
curpoke = 13;
else
curpoke = 12;
}
poke[2][curpoke]--;
hand[2]--;
table[curpoke]++;
if (poke[3][rndpoke] == 4)
{
for (int i = 1; i <= 13; i++)
{
poke[2][i] += table[i];
hand[2] += table[i];
table[i] = 0;
}
}
else if(hand[2]==0)
{
for (int i = 1; i <= 13; i++)
{
poke[2][i] += table[i];
hand[2] += table[i];
table[i] = 0;
}
}
else if (1 + poke[1][rndpoke] > 4)
{
for (int i = 1; i <= 13; i++)
{
poke[2][i] += table[i];
hand[2] += table[i];
table[i] = 0;
}
}
}
}
else if (rndplayer == 3)
{
if (poke[3][rndpoke])
{
int num = poke[3][rndpoke];
hand[3] -= num;
poke[3][rndpoke] = 0;
table[rndpoke] += num;
if (hand[3] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[4][i] += table[i];
hand[4] += table[i];
table[i] = 0;
}
}
else if (num + poke[1][rndpoke] > 4)
{
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
}
else
{
int minnum = 4;
for (int i = 1; i <= 13; i++)
if (poke[3][i])
minnum = min(minnum, poke[3][i]);
int curpoke = -1;
if (poke[3][10] == minnum)
curpoke = 10;
if(curpoke==-1)
for(int i=2;i<=9;i++)
if (poke[3][i] == minnum)
{
curpoke = i;
break;
}
if (curpoke == -1)
if (poke[3][1] == minnum)
curpoke = 1;
else if (poke[3][11] == minnum)
curpoke = 11;
else if (poke[3][13] == minnum)
curpoke = 13;
else
curpoke = 12;
hand[3] -= minnum;
poke[3][curpoke] = 0;
table[curpoke] += minnum;
if (hand[3] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[3][i] += table[i];
hand[3] += table[i];
table[i] = 0;
}
}
else if (minnum + poke[1][rndpoke] > 4)
{
for (int i = 1; i <= 13; i++)
{
poke[3][i] += table[i];
hand[3] += table[i];
table[i] = 0;
}
}
}
}
else if (rndplayer == 4)
{
if (poke[4][rndpoke] == 3 || poke[4][rndpoke] == 4)
{
int num = poke[4][rndpoke];
hand[4] -= num;
poke[4][rndpoke] = 0;
table[rndpoke] += num;
int nextrndpoke = rndpoke + 1;
nextrndpoke = (nextrndpoke - 1) % 13 + 1;
if (num + poke[1][rndpoke] > 4 || poke[1][nextrndpoke] == 0)
{
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
else if (poke[3][rndpoke] == 4)
{
for (int i = 1; i <= 13; i++)
{
poke[3][i] += table[i];
hand[3] += table[i];
table[i] = 0;
}
}
}
else
{
int num1 = poke[4][rndpoke];
hand[4] -= num1;
poke[4][rndpoke] = 0;
table[rndpoke] += num1;
int num2=0;
if (hand[4])
num2 = 1;
int curpoke = -1;
if (poke[4][10])
curpoke = 10;
if (curpoke == -1)
{
for (int i = 2; i <= 9; i++)
if (poke[4][i])
{
curpoke = i;
break;
}
}
if (curpoke == -1)
if (poke[4][1])
curpoke = 1;
else if (poke[4][11])
curpoke = 11;
else if (poke[4][13])
curpoke = 13;
else
curpoke = 12;
if (num2)
{
poke[4][curpoke] -= num2;
table[curpoke] += num2;
hand[4] -= num2;
}
int nextrndpoke = rndpoke + 1;
nextrndpoke = (nextrndpoke - 1) % 13 + 1;
if (num1 + num2 + poke[1][rndpoke] > 4 || poke[1][nextrndpoke] == 0)
{
if(num2)
for (int i = 1; i <= 13; i++)
{
poke[4][i] += table[i];
hand[4] += table[i];
table[i] = 0;
}
else
for (int i = 1; i <= 13; i++)
{
poke[1][i] += table[i];
hand[1] += table[i];
table[i] = 0;
}
}
else if (poke[3][rndpoke] == 4)
{
for (int i = 1; i <= 13; i++)
{
poke[4][i] += table[i];
hand[4] += table[i];
table[i] = 0;
}
}
}
}
}
for (int i = 1; i <= 4; i++)
{
if (hand[i] == 0)
cout << "WINNER" << endl;
else
{
for (int j = 1; j <= 13; j++)
{
while (poke[i][j])
{
if (j == 1)
cout << "A";
else if (2 <= j && j <= 10)
cout << j;
else if (j == 11)
cout << "J";
else if (j == 12)
cout << "Q";
else if (j == 13)
cout << "K";
poke[i][j]--;
hand[i]--;
if (hand[i] == 0)
cout << endl;
else
cout << " ";
}
}
}
}
}
return 0;
}
D - 80 Days
题意:
初始有c个钱,按照一个环遍历n个城市,到达每个城市可以获得a元,离开时花费b元,问从哪个城市出发,能遍历n个城市
题解:
尺取,假设从1号城市出发,先后向遍历到不能遍历的城市,再将出发城市向后移,知道又能遍历新的城市,如此循环
#include<bits/stdc++.h>
#define FOR(I,S,T) for(int I=(S);I<=(T);I++)
#define pb push_back
#define mp make_pair
#define eb emplace_back
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 2;
int l, r;
int n, k;
ll sum;
int a[maxn];
int main() {
int T;
cin >> T;
while (T--){
sum = 0;
scanf("%d%d", &n, &k);
FOR(i,1,n) scanf("%d", &a[i]);
FOR(i,1,n) {
int x; scanf("%d", &x);
a[i] -= x;
}
FOR(i,1,n) a[i+n] = a[i];
l = 1, r =1;
sum += a[1];
while (r < 2 * n){
sum += a[++r];
while (l <= r && sum < -k) sum-=a[l],l++;
//cout << sum << " " << l <<" " << r << endl;
if (r - l + 1>= n) break;
}
if (l == 0) l++;
if (r - l + 1>= n) printf("%d\n", l);
else printf("-1\n");
}
return 0;
}
G - The Mole
题意:平面上n个线段,给一个点,问到最近的线段的矩阵的距离,数据随机
题解:分块暴力
先将平面分块,然后再暴力计算周围的9个方块,如果没有,就暴力所有的线段
这种解法有问题,有返例,但是有个学弟这个写过了
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const int N=1e4+5;
const int M=256;
const double eps=1e-8;
vector<int> v[M+1][M+1];
struct Point{
double x,y;
Point(double _x=0,double _y=0):x(_x),y(_y){}
void in()
{
scanf("%lf%lf",&x,&y);
}
Point operator -(const Point &b)const {
return Point(x-b.x,y-b.y);
}
Point operator +(const Point &b)const {
return Point(x+b.x,y+b.y);
}
bool operator ==(const Point &b)const {
return x==b.x&&y==b.y;
}
double operator ^(const Point &b)const {
return x*b.y-y*b.x;
}
double operator *(const Point &b)const {
return x*b.x+y*b.y;
}
double distance(Point p){
return hypot(x-p.x,y-p.y);
}
void getid(int &a,int &b){
a=x/M,b=y/M;
}
};
struct Line{
Point s,e;
void in(){
s.in();
e.in();
}
void setid(int id){
int a,b,aflag,bflag;
Point tem=e-s;
for(int i=0;i<=M;i++)
{
Point p=s+Point(tem.x*i/M,tem.y*i/M);
p.getid(a,b);
if(a==aflag&&b==bflag)
continue;
v[a][b].push_back(id);
aflag=a,bflag=b;
}
}
double dispointtoseg(Point p){
if(s==e)
return p.distance(s);
if((p-s)*(e-s)<-eps)
return p.distance(s);
if((p-e)*(s-e)<-eps)
return p.distance(e);
return fabs((s-p)^(e-p))/s.distance(e);
}
};
int vis[N]={-1};
Line l[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
l[i].in();
l[i].setid(i);
}
while(m--)
{
Point p;
p.in();
int ans=1,xblock,yblock;
double tem=1e50;
p.getid(xblock,yblock);
for(int i=xblock-1;i<=xblock+1;i++)
for(int j=yblock-1;j<=yblock+1;j++)
{
if(i<0)
break;
if(j<0)
continue;
for(int k=0;k<(int)v[i][j].size();k++)
{
if(vis[v[i][j][k]]==m)
continue;
vis[v[i][j][k]]=m;
double dis=l[v[i][j][k]].dispointtoseg(p);
if(dis+eps<tem)
tem=dis,ans=v[i][j][k]+1;
else if(fabs(dis-tem)<eps)
ans=min(ans,v[i][j][k]+1);
}
}
if(tem==1e50)
for(int i=0;i<n;i++)
{
double dis=l[i].dispointtoseg(p);
if(dis+eps<tem)
tem=dis,ans=i+1;
else if(fabs(dis-tem)<eps)
ans=min(ans,i+1);
}
printf("%d\n",ans);
}
return 0;
}
H - K-Dimensional Foil II
题意:平面上某一点到,求K维菱形的最短距离
题解:几何数学
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100+2;
int c[maxn], a2[maxn], a[maxn], s[maxn];
int r;
double ans[maxn];
void solve(int k){
double dif = 0.0,num = 0.0;
for (int i = 0; i < k; i++){
num += a[i]*s[i];
dif += a[i]*a[i];
}
num -= r;
double t = num / dif;
bool flag=1;
for (int i = 0; i < k; i++){
ans[i] = s[i] - a[i] * t;
if (ans[i] < 0) s[i] = a[i] = ans[i] = 0, flag=0;
}
if (!flag) solve(k);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,K;
scanf("%d%d", &n, &K);
scanf("%d",&r);
for (int i = 0; i < K; i++)
scanf("%d", &c[i]);
for (int t = 0; t < n; t++){
memset(ans, 0, sizeof(ans));
for (int i = 0; i < K; i++){
scanf("%d",&s[i]);
s[i] -= c[i];
a2[i] = s[i] > 0 ? 1 : -1;
if (s[i]==0) a2[i] = 0;
a[i] = (a2[i] != 0);
s[i] = abs(s[i]);
}
solve(K);
for (int i = 0; i < K; i++){
printf("%.8f",ans[i]*a2[i]+c[i]);
if (i!= K-1) putchar(' ');
else putchar('\n');
}
}
}
}