2020 ICPC 南京站

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(1p)x(nx+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:KCoprimePermutation

题目大意

给你一个 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(i1,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:LetsPlayCurling

题目大意

给你一个序列 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=0123n时的最低总能量花费分别为多少。

分析

这个题目可以等价于:我选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 
*   ┃        ┣┓
*    ┃        ┏┛
*     ┗┓┓┏━┳┓┏┛ + + + +
*    ┃┫┫ ┃┫┫
*    ┗┻┛ ┗┻┛+ + + +
*/


猜你喜欢

转载自blog.csdn.net/tlyzxc/article/details/114125245