A. Split it!

题意

给定一个为的字符串和一个数

然后为是否存在个非空字符串使得
$R(abcd) = dcba$

首先不管我们每一个字符串取多少 即然他要求是非空字串 那么 前面k个字符就一定要和最后k个字符是要相反的才有可能存在

我们可以这样来想 举一个例子
$k=2$

于是乎我们可以取

这样就刚好符合条件

那么我们继续去缩小每一个的取值范围

当我们取到的时候 无论就已经可以确定可以符合条件了

因为第一个刚好等于最后一个 第二个刚好等于倒数第二个 因此中间的是什么就已经不必要了

所以我们就可以推出来

只要前面k个字符和最后k个字符是相反的就有可能存在了

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
const ll MOD = 1e9 + 7;

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
char s[N];

void solve(){
    int n , k;
    scanf("%d%d", &n , &k);
    getchar();
    for(int i = 1 ; i <= n ; ++i)  
        scanf("%c" , &s[i]);
    if(k * 2 >= n){
        cout<<"NO"<<endl;
        return ;
    }
    for(int i = 1 ; i <= k ; ++i){
        if(s[i] != s[n - i + 1]){
            cout<<"NO"<<endl;
            return ;
        }
    }
    cout<<"YES"<<endl;
}

int main(void){
    int T;
    scanf("%d" , &T);
    while(T--)
        solve();

    return 0;
}

B. Max and Mex

题意

给出个数字组成一个序列 和次操作 每次操作选择序列中最大的数字a和序列中所缺的最小非负整数b 然后将 插入 序列中 然后求在次操作之后 序列中有多少个不同的数字

比如0 1 3 4 序列中最大的数字就是4 所缺的最小非负整数是2 然后就将3插入序列 这个时候序列中就有四个不同的数字

如果直接的去暴力 很明显会超时 所以我们先研究一下这个

就比如上面这个例子 不管操作多少次 我们都无法将最小的负整数增大 也就是說不管怎么弄 序列的数字都不会加一

那么我们再看什么情况会加一 如果上面那个例子没有3 也就是算出来的小于最大的数字 然后可以加上去

还有一个就是最小整数大于最大整数 就比如这个序列

最小负整数是5 最大的整数是 4 算出一个5 然后将5插入 如果再操作就再插入一个6

这样操作几次就插入几个

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
const ll MOD = 1e9 + 7;

const int N = 1e9 + 7;
const int INF = 0x3f3f3f3f;

map<int ,int >mp;

int findmin(int d){
    for(int i = 0 ; i <= d ; ++i){
        if(!mp[i])  return i;
    }
}

void solve(){
    int n , k , maxn = -1 , minn = 0 , x;
    int sum = 0;
    mp.clear();
    scanf("%d%d" , &n , &k);
    for(int i = 1  ; i <= n ; ++i){
        scanf("%d" , &x);
        if(x > maxn)    maxn = x;
        if(!mp[x]){
            sum += 1;
        }
        mp[x] = 1;
        if(x == minn){
            while(mp.count(minn))   minn++;
        }
    }
    for(int i = 1 ; i <= k ; ++i){
        x = ceil( ((double)maxn + minn) / 2.0);
        if(x > maxn){
            sum += k;
            break;
        }
        if(maxn == minn || mp[x])   break;
        if(x > maxn) maxn = x;
        if(x == minn){
            while(mp[minn]) minn++;
        }
        sum++;
        mp[x] = 1;

    }
    printf("%d\n"  , sum);
}

int main(void){
    int T ;
    scanf("%d" , &T);
    while(T--)
        solve();

    return 0;
}

C. Diamond Miner

题意

个矿工和个矿 矿工在轴上 矿在轴上 一个矿工挖一个矿 一个矿也只能挖一个矿工 然后求出矿工和对应的矿的距离 求距离的综合的最小值

小的挖小的就好了

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
const ll MOD = 1e9 + 7;

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
double a[N] , b[N];

bool cmp(double a , double b){
    return abs(a) < abs(b);
}

void solve(){
    int n ;
    scanf("%d" , &n);
    double x , y;
    int cnt1 = 0 , cnt2 = 0;
    for(int i = 1 ; i <= n * 2 ; ++i){
        scanf("%lf%lf" , &x , &y);
        if(x == 0){
            a[++cnt1] = y;
        }
        else{
            b[++cnt2] = x;
        }
    }
    sort(a + 1 , a + 1 + cnt1 , cmp);
    sort(b + 1 , b + 1 + cnt2 , cmp);
    double ans = 0;
    for(int i = 1 ; i <= n ; ++i){
        ans += (sqrt(a[i] * a[i] + b[i] * b[i]));
    }
    printf("%.12lf\n" , ans);
}

int main(void){
    int T;
    scanf("%d" , &T);
    while(T--)
        solve();

    return 0;
}

D. Let's Go Hiking

题意

给定一个 个点 在一条直线上 然后每一个点都有一个值 a和b进行博弈 a线选一个点 然后b再选一个点 a和b都只能在相邻的点上移动 并且a只能向小于自己所在的点的反向移动 b只能向大于自己所在的点移动 谁先不能移动就算谁落败 求所有a能够获胜的点的个数

直接拿一个样例来说 1 2 5 4 3 有且只有 a选择第三个点的时候 也就是值为5的这个点 a是必胜的

因为当a选择5的时候 b的选择就是 1 2 4 3

如果b选择2和4 那么a就向另一个方向走 比如 b选择2 那么a就向4 走

流程就是 5->4 2->5 4->3这个时候轮到b了但是b无法移动

然后如果选择1或者3 那那么比如1

流程就是 5->2 这个时候b就无法移动了 也就是说当a选择第三个点的时候 a是必胜的

很明显 我们就可以看到 如果a只能走左右两边的一边 那是必输无疑的 只要b堵住他就可以了

如果有一条路比另一条路长 那么b只要选择长的一条就好了 然后在最远的偶数位置等着他 a就必胜 因为左右两边相同时 如果a向没有b的一个方向走 因为a先行动 那么一定也是a最先动不了 b只要待在最远的地方就好了

由此我们就可以发现 a唯一的获胜方式就是 有两条路 并且b只能面向a走来 最后b走不了 因此 就可以得到 唯一的获胜条件就是两条路的长度相同且为奇数

然后我们还要排除一种情况 就是存在另一条道路的长度和这两条的长度相同 这样b也是只要无脑选另一条就因为 因为a先走 所以长度相同时还是b获胜

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
const ll MOD = 1e9 + 7;

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;

int l[N] , r[N];
int a[N];

void solve(){
    int n ;
    scanf("%d" , &n);
    int maxn = -1;
    for(int i = 1 ; i <= n ; ++i){
        scanf("%d" , &a[i]);
    }
    l[1] = r[n] = 1;
    for(int i = 2 ; i <= n ; ++i){
        if(a[i] > a[i - 1]){
            l[i] = l[i - 1] + 1;
        }
        else l[i] = 1;
    }
    for(int i = n - 1; i >= 1 ; --i){
        if(a[i] > a[i + 1]){
            r[i] = r[i + 1] + 1;
        }
        else r[i] = 1;
    }
    int top = -1;
    int cnt = 0;
    for(int i = 1 ; i <= n ; ++i){
        // cout<<r[i]<<" ";
        if(l[i] > maxn || r[i] > maxn){
            top = i;
            cnt = 1;
            maxn = max(l[i] , r[i]);
        }
        else if(l[i] == maxn || r[i] == maxn){
            cnt++;
        }
    }
    if(cnt > 1){
        cout<<"0"<<endl;
        return ;
    }
    int shortlen = (maxn == l[top]) ?   r[top] : l[top];
    if(maxn & 1 && shortlen == maxn)    cout<<"1"<<endl;
    else cout<<"0"<<endl;
}

int main(void){
    solve();

    return 0;
}