第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)
- E : E v i l C o o r d i n a t e \mathbf{E:Evil Coordinate} E:EvilCoordinate
- F : F i r e w o r k s \mathbf{F:Fireworks} F:Fireworks
- K : K C o − p r i m e P e r m u t a t i o n \mathbf{K:K Co-prime Permutation} K:KCo−primePermutation
- L : L e t ′ s P l a y C u r l i n g \mathbf{L:Let's Play Curling} L:Let′sPlayCurling
- M : M o n s t e r H u n t e r \mathbf{M:Monster Hunter} M:MonsterHunter
E : E v i l C o o r d i n a t e \mathbf{E:Evil Coordinate} E:EvilCoordinate
题目大意
在一个图中,起点是 ( 0 , 0 ) (0,0) (0,0) ,给你一个行走顺序,问你能不能通过改变这个行走顺序来避开地雷点 ( m x , m y ) (mx,my) (mx,my)
分析
当时看起来感觉很复杂,分类讨论了半天一个方向走到头是肯定可以构造出答案的,所以,我们可以全排列这四个方向
其实可以证明一下,如果有解的话,那么我们可以将这四个方向进行全排列,然后判断合法性
需要特判一下,如果起点和终点就是地雷点的话,那么无论我怎么改变方向都是无法避开的
最后需要注意一下方向数组每次都需要初始化一下
代码
#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-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;}
int x,y;
char str[N];
int d[5];
int a[] = {1,2,3,4};
map<int,PII> M;
map<char,int> p;
map<int,char> c;
bool run(){
int p1 = 0,p2 = 0;
for(int i = 0;i < 4;i++)
for(int j = 0;j < d[a[i]];j++){
p1 += M[a[i]].fi;
p2 += M[a[i]].se;
if(p1 == x && p2 == y) return false;
}
return true;
}
int main(){
int T;
read(T);
p['R'] = 1;p['D'] = 2;p['L'] = 3;p['U'] = 4;
c[1] = 'R',c[2] = 'D',c[3] = 'L',c[4] = 'U';
M[1] = {1,0};M[2] = {0,-1};M[3] = {-1,0};M[4] = {0,1};
while(T--){
memset(d,0,sizeof d);
a[0] = 1,a[1] = 2,a[2] = 3,a[3] = 4;
read(x),read(y);
scanf("%s",str);
for(int i = 0;str[i];i++) d[p[str[i]]]++;
int dx = 0,dy = 0;
for(int i = 1;i <= 4;i++){
dx += d[i] * M[i].fi;
dy += d[i] * M[i].se;
}
if(dx == x && dy == y){
puts("Impossible");
continue;
}
if(x == 0 && y == 0){
puts("Impossible");
continue;
}
bool flag = false;
do{
if(run()){
for(int i = 0;i < 4;i++)
for(int j = 0;j < d[a[i]];j++)
printf("%c",c[a[i]]);
puts("");
flag = true;
break;
}
}while(next_permutation(a,a + 4));
if(!flag) puts("Impossible");
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
F : F i r e w o r k s \mathbf{F:Fireworks} F:Fireworks
题目大意
你每制作一枚烟花需要 n n n分钟,释放所有的烟花需要 m m m分钟,没只烟花成功的概率为 p p p,问你在采取最优策略的前提下,直到成功释放第一个烟花时最小的期望时间花费。
分析
因为是计算最优期望,我们可以一次制作多枚然后全部点燃,那么公式就是
f
(
x
)
=
(
n
∗
x
+
m
)
1
−
(
1
−
p
)
x
f(x) = \frac{(n * x + m)}{1 - (1 - p)^x}
f(x)=1−(1−p)x(n∗x+m)
盲猜这是一个单峰函数,用一下三分求一下最大值出现的位置,最后需要注意一下烟花数量需要取整即可
代码
#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-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;}
double n,m,p,q;
double f(double mid){
double res = (n * mid + m) / (1.0 - pow(q,mid));
return res;
}
int main(){
int T;
read(T);
while(T--){
scanf("%lf%lf%lf",&n,&m,&p);
q = 1.0 - p / 10000;
double l = 1,r = 1e9;
while(r - l > eps){
double mid = l + (r - l) / 3.0;
double midmid = r - (r - l) / 3.0;
if(f(mid) > f(midmid))
l = mid;
else
r = midmid;
}
int t = l;
printf("%.10lf\n",min(f(t),f(t + 1)));
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
K : K C o − p r i m e P e r m u t a t i o n \mathbf{K:K Co-prime Permutation} K:KCo−primePermutation
题目大意
给你一个 n n n和一个 k k k,你需要构造一个1 ∼ \sim ∼ n的全排列 a i a_{i} ai,需要保证有 k k k个数字满足 g c d ( a [ i ] , i ) = = 1 gcd(a[i],i) == 1 gcd(a[i],i)==1
分析
其实就是一个构造,只需要知道 g c d ( i − 1 , i ) = 1 gcd(i - 1,i) = 1 gcd(i−1,i)=1即可
代码
#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-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;}
int main(){
int n,k;
read(n),read(k);
if(!k){
puts("-1");
return 0;
}
cout << k;
for(int i = 1;i < k;i++) cout << ' ' << i;
for(int i = k + 1;i <= n;i++) cout << ' ' << i;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
L : L e t ′ s P l a y C u r l i n g \mathbf{L:Let's Play Curling} L:Let′sPlayCurling
题目大意
给你一个序列 a n a_{n} an和 b m b_{m} bm,每个数组中的数代表着当前各个队伍有的 s t o n e stone stone的位置。选定一个位置 c c c,如果存在一个红队的石头到 c c c的距离小于所有蓝队的石头到 c c c的距离,那么红队积一分,问c选最合适的地方的时候红队的最高得分是多少,如果不存在方案则输出 I m p o s s i b l e Impossible Impossible
分析
这道题挺有迷惑性的,我一直在找点,最后才发现原来这个最高分可以直接算出来
首先我们先将
a
b
ab
ab序列排序,然后推一下会发现,
b
i
b_{i}
bi和
b
i
+
1
b _{i + 1}
bi+1之内,如果存在
a
a
a序列,那么一定可以找到位置
c
c
c保证这个区间内的所有
a
i
a_{i}
ai都得分,这个区间外的所有点都无法得分
所以其实就是二分计算区间内的数量,然后加上一个边界即可
代码
#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-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;}
int a[N],b[N];
int n,m;
int main(){
int T;
read(T);
while(T--){
read(n),read(m);
for(int i = 1;i <= n;i++) read(a[i]);
for(int i = 1;i <= m;i++) read(b[i]);
sort(a + 1,a + 1 + n);
sort(b + 1,b + 1 + m);
m = unique(b + 1,b + m + 1) - b - 1;
b[0] = 0,b[++m] = INF;
int ans = 0;
for(int i = 1;i <= m;i++){
int r = lower_bound(a + 1,a + 1 + n,b[i]) - a - 1;
int l = upper_bound(a + 1,a + 1 + n,b[i - 1]) - a;
ans = max(ans,r - l + 1);
}
if(!ans) puts("Impossible");
else di(ans);
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
M : M o n s t e r H u n t e r \mathbf{M:Monster Hunter} M:MonsterHunter
题目大意
给你一颗树,树上每个节点都是一个 h p i hp_{i} hpi血量的怪物。打败每个怪物所需要的能量值为 h p i hp_{i} hpi + 所 有 存 活 的 直 接 子 节 点 的 h p j hp_{j} hpj 。每次必须要消灭父节点后才能消灭子节点。此外你还有m个魔咒,每个魔咒可以不耗费能量且可以消灭任意一个存活的怪物。问你 m = 0 , 1 , 2 , 3 … n m=0,1,2,3…n m=0,1,2,3…n时的最低总能量花费分别为多少。
分析
这个题目可以等价于:我选m个点最少需要多少花费,转化成一个树上依赖背包问题
需要注意一下,只有当子节点被选择,同时父节点也被选择的时候,才可以进行状态转移
代码
#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 = 2e3 + 10;
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;}
int n;
ll f[2][N][N];
int h[N],ne[N],e[N],idx;
int si[N];
ll w[N];
void init(){
for(int i = 0;i <= n;i++){
h[i] = -1;
for(int j = 0;j <= n;j++)
f[1][i][j] = f[0][i][j] = 1e18;
}
idx = 0;
}
void add(int x,int y){
ne[idx] = h[x],e[idx] = y,h[x] = idx++;
}
void dfs(int u){
f[1][u][1] = w[u];
f[0][u][0] = 0;
si[u] = 1;
for(int i = h[u];~i;i = ne[i]){
int j = e[i];
dfs(j);
for(int l1 = si[u];~l1;l1--)
for(int l2 = si[j];~l2;l2--){
f[0][u][l1 + l2] = min(f[0][u][l1 + l2],f[0][u][l1] + min(f[0][j][l2],f[1][j][l2]));
f[1][u][l1 + l2] = min(f[1][u][l1 + l2],f[1][u][l1] + min(f[0][j][l2],f[1][j][l2] + w[j]));
}
si[u] += si[j];
}
}
void solve(){
read(n);
init();
for(int i = 2;i <= n;i++){
int x;
read(x);
add(x,i);
}
for(int i = 1;i <= n;i++) read(w[i]);
dfs(1);
return;
}
void print(){
for(int i = n;~i;i--) printf("%lld ",min(f[1][1][i],f[0][1][i]));
puts("");
}
int main(){
int T;
read(T);
while(T--){
solve();
print();
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/