2017-2018 ACM-ICPC NEERC Southern Subregional Contest(3)

*A. Automatic Door

题意

分析


*C

题意

分析


*G

题意

 

分析

 


E.Field of Wonders

签到


F. Lost in Transliteration

签到


M. Quadcopter Competition

签到


H. Palindromic Cut

题意

给一个长度为n的字符串,尽可能的少的分成长度相同的回文串,输出回文串个数,以及每个回文串


 分析

考虑回文串,直接将字符分成两类,能回文的长度为2的串(eg:aa),长度为1的串(eg:a),然后暴力分别算出数量令前者sum1,后者sum2,暴力找到sum1%sum2==0的情况(2可以分成两个1),然后输出即可 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<time.h>
#define ll long long
using namespace std;
#define mp make_pair
#define pb push_back
#define lson l,mid,pos<<1
#define rson mid+1,r,pos<<1|1
const double PI=acos(-1);
const int maxm=2000+5;
//const int maxn=1e5+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
//int dir[4][2]={0,1,1,0,0,-1,-1,0};
//ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
//ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
//ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
//ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}


vector<char> odd,even;
int n,cnt[300];
char str[400010], ans[400010];
int main()
{
    scanf("%d",&n);
    scanf("%s",str+1);
    for (int i=1;i<=n;i++)
        cnt[str[i]]++;
    for (int i=0;i<=256;i++)
        if (cnt[i])
        {
            if (cnt[i]&1)
            {
                cnt[i]--;
                odd.push_back(i);
            }
            for (int j=1;j<=cnt[i]/2;j++)
                even.push_back(i);
        }
    if (odd.size()==0)
    {
        for (int i=1;i<=n/2;i++)
            ans[i]=ans[n-i+1]=even[i-1];
        printf("1
");
        for (int i=1;i<=n;i++)
            printf("%c",ans[i]);
        return 0;
    }
    else
    {
        while (even.size()%odd.size())
        {
            odd.push_back(even.back());
            odd.push_back(even.back());
            even.pop_back();
        }
        printf("%d
",(int)odd.size());
        for (int i=1;i<=(int)odd.size();i++)
        {
            ans[(n/odd.size())/2]=odd[i-1];
            for (int j=1;j<=n/odd.size()/2;j++)
                ans[(n/odd.size()/2)-j]=ans[(n/odd.size()/2)+j]=even.back(),even.pop_back();
            for (int j=0;j<n/odd.size();j++) printf("%c",ans[j]);
            printf(" ");
        }
    }
    return 0;
}
View Code

*I. Photo Processing

题意

给n个数分组,每组至少分k个数(不要求连续分),每组的mex值为每组的max-min,这n个数的mex为所有组mex的max,使这个max最小,并求出这个数


分析

很容易下想到,二分答案,check(mid)用dp,dp[i]表示1~i可以分组的最远位置

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<time.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
using namespace std;
#define mp make_pair
#define pb push_back
#define lson l,mid,pos<<1
#define rson mid+1,r,pos<<1|1
const double PI=acos(-1);
const int maxm=2000+5;
const int maxn=3e5+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
//int dir[4][2]={0,1,1,0,0,-1,-1,0};
//ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
//ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
//ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
//ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}

int n, k;
int a[maxn];
int dp[maxn];

bool check(int answer)
{
     int id = 0;
     for(int i = k; i <= n; i++)
     {
         int point = dp[i-k];
         if((a[i]-a[dp[i-k]+1]) <= answer) id = i;
         dp[i] = id;
     }
     if(dp[n] == n)
        return true;
     else
        return false;
}

int  main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n;i++)
    {

        scanf("%d", &a[i]);
    }
    sort(a+1,a+n+1);
    int l = 0, r = 1000000000;
    while(l < r)
    {
        int mid = (l+r)/2;
        if(check(mid))
        {
            r = mid;
        }
        else
        {
            l = mid+1;
        }
    }
    printf("%d
", l);
    return 0;
}
View Code

K. Road Widening

题意

给n条路,每条路都有一个初始的宽度和一个最多可以加的宽度,现要求每条路的最终宽度S[i],满足 |s'i + 1 - s'i| ≤ 1  (1 <= i < n)都成立,问所有路最多能加多少(和)以及每条路最终的宽度, 没有满足条件的解输出-1


分析

分析可得这道题和两个区间的关系有一定联系(六种情况)?

首先可以否定的是从前往后或者从后往前尽可能多的取,因为可能不满足题意,其实很直观的是维护每个点的合法区间(通过上下两个区间关系,画出两个区间观察就可以看出来),下面就是如何维护合法区间,从前往后扫一边维护每一个点的合法区间的左右端点,从前往后扫的时候 i 和 i-1形成了一个制约关系, 不难理解一个位置i的值得确定和左右两边的数都有关系,所以在从后往前扫一遍求出每个位置具体的值即可

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n;
int a[maxn], g[maxn], xmax[maxn], xmin[maxn];
int now[maxn];

int main()
{
    scanf("%d", &n);
    long long sum = 0, ans = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d", &a[i], &g[i]);
        g[i] = a[i]+g[i];
    }
    xmax[1] = g[1];
    xmin[1] = a[1];
    for(int i = 2; i <= n; i++)
    {
        xmax[i] = min(g[i], xmax[i-1]+1);
        xmin[i] = max(a[i], xmin[i-1]-1);
        if(xmax[i] < xmin[i])
        {
            printf("-1
");
            return 0;
        }
    }
    sum += xmax[n] - a[n];
    ans = xmax[n];
    now[n] = xmax[n];
    for(int i = n-1; i >= 1; i--)
    {
        if(ans+1 <= xmax[i])
          ans = ans+1;
        else if(ans<=xmax[i])
          ans =ans;
          else
            ans = ans -1;
         now[i]=ans;
        sum += ans-a[i];

    }
    printf("%I64d
", sum);
    for(int i = 1; i <= n; i++)
    printf("%d%c", now[i],i==n?'
':' ');
    return 0;
}
View Code
要么优秀要么生锈
原文地址:https://www.cnblogs.com/Superwalker/p/7845685.html