跳转至

2021-02-09-2月9日题解

image-20210209214610853

题解

用线段树来维护某一区间的最小值,然后对 (0,n-1) 每一个数进行查询,定位到该数所在的最小区间(注意特判一个最小值对应多个区间这种情况),然后对该区间的最小值的 最小值 进行查询,如果这个区间的最小值都比该值大,则输出-1。

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
    ll l,r,pos,min1,add;
};
ll n,q;
node tree[400500]={0};
struct node1
{
    ll l,r;
};
vector<node1>v[100500];
ll num[100500]={0};
void build(ll t,ll l,ll r)
{
    tree[t].pos=l;
    tree[t].l=l;
    tree[t].r=r;
    tree[t].min1=-1;
    tree[t].add=-1;
    if(l==r)
        return ;
    ll mid=(l+r)/2;
    build(2*t,l,mid);
    build(2*t+1,mid+1,r);
    return ;
}
void push_up(ll p)
{
    if(tree[p*2].min1<tree[p*2+1].min1){
        tree[p].min1=tree[p*2].min1;
        tree[p].pos=tree[p*2].pos;
    }else {
        tree[p].min1=tree[p*2+1].min1;
        tree[p].pos=tree[p*2+1].pos;
    }
    return ;
}
void push_down(ll t)
{
    if(tree[t].add==-1)
        return ;
    tree[2*t].add=max(tree[t].add,tree[2*t].add);   ///最小值中取最大
    tree[2*t+1].add=max(tree[t].add,tree[2*t+1].add);

    tree[2*t].min1=max(tree[t].min1,tree[2*t].min1);
    tree[2*t+1].min1=max(tree[t].min1,tree[2*t+1].min1);

    tree[t].add=-1;
    return ;
}
void update(ll t,ll l,ll r,ll x)
{
    if(l==tree[t].l&&r==tree[t].r)
    {
        tree[t].add=max(tree[t].add,x);
        tree[t].min1=max(tree[t].min1,x);
        return ;
    }
    push_down(t);
    ll mid=(tree[t].l+tree[t].r)/2;
    if(r<=mid)
        update(2*t,l,r,x);
    else if(l>mid)
        update(2*t+1,l,r,x);
    else
    {
        update(2*t,l,mid,x);
        update(2*t+1,mid+1,r,x);
    }
    push_up(t);
    return ;
}
void update(ll t,ll pos)
{
    if(tree[t].l==tree[t].r)
    {
        tree[t].min1=1e9;
        return ;
    }
    push_down(t);
    ll mid=(tree[t].l+tree[t].r)/2;
    if(pos<=mid)
        update(2*t,pos);
    if(pos>mid)
        update(2*t+1,pos);
    push_up(t);
    return ;
}
node query(ll t,ll l,ll r)
{
    if(tree[t].l==l&&tree[t].r==r)
    {
        return tree[t];
    }
    push_down(t);
    ll mid=(tree[t].l+tree[t].r)/2;
    if(r<=mid)
        return query(2*t,l,r);
    else if(mid<l)
        return query(2*t+1,l,r);
    else
    {
        node tree1=query(2*t,l,mid);
        node tree2=query(2*t+1,mid+1,r);
        if(tree1.min1<tree2.min1)
            return tree1;
        else
            return tree2;
    }
}
int main()
{
    scanf("%lld%lld",&n,&q);
    build(1,1,n);
    for(ll i=1;i<=q;i++)
    {
        ll l,r,x;
        scanf("%lld%lld%lld",&l,&r,&x);
        l++,r++,x++;
        update(1,l,r,x);
        v[x].push_back({l,r});
    }
    ll flag=1;
    for(ll x=1;x<=n&&flag;x++)
    {
        ll l=1,r=n;
        for(int i=0;i<v[x].size();i++)
        {
            l=max(l,v[x][i].l);
            r=min(r,v[x][i].r);
        }
        if(l>r)   ///一个最小值对应多个区间的情况
        {
            flag=0;
            break;
        }
        node ans=query(1,l,r);
        if(ans.min1>x)
        {
            flag=0;
            break;
        }
        ll pos=ans.pos;
        num[pos]=x-1;
        update(1,pos);
    }
    if(!flag)
    {
        for(ll i=1;i<=n;i++)
        {
            printf("-1 ");
        }
        printf("\n");
    }
    else
    {
        for(ll i=1;i<=n;i++)
        {
            printf("%d ",num[i]);
        }
        printf("\n");
    }
    return 0;
}

image-20210209205552652

题解

路径可以拼凑成一个长方形,只需要暴力找到这个长方形即可,注意如果两个点在同一条直线上则需要将两个点错开。

代码
#include <stdio.h>
#include <math.h>
#include <bits/stdc++.h>
using namespace std;
int x1,x2,y1,y2;
int px,py,dis=0;
int judge1(int x,int y)
{
    int dis1=abs(x1-x)+abs(y1-y);
    if(dis1>dis)
        px=x,py=y,dis=dis1;
}
int main()
{
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    if(x1==x2)
        x1++;
    if(y1==y2)
        y1++;
    judge1(x2+1,y2+1);
    judge1(x2+1,y2);
    judge1(x2+1,y2-1);
    judge1(x2,y2+1);
    judge1(x2,y2-1);
    judge1(x2-1,y2+1);
    judge1(x2-1,y2);
    judge1(x2-1,y2-1);
    printf("%d\n",dis*2);
}

image-20210209215603046

题解

根据题意直接标记模拟即可。

代码
#include <stdio.h>
#include <math.h>
#include <bits/stdc++.h>
using namespace std;
char a[2000]={0};
map<char,int>s;
map<int,int>k;
char b[2000][2000]={0};
map<char,int>mp1;
map<char,int>mp;
int main()
{
    int n;
    scanf("%d",&n);
    scanf("%s",a+1);
    for(int i=1;i<=n;i++)
    {
        if(a[i]=='*')
            k[i]=1;
        else
            s[a[i]]=1;
    }
    int m;
    scanf("%d",&m);
    int sum=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%s",b[++sum]+1);
        int flag=1;
        for(int j=1;j<=n&&flag;j++)
        {
            if(k[j]&&s[b[sum][j]])
                flag=0;
            else if(!k[j]&&b[sum][j]!=a[j])
                flag=0;
        }
        if(!flag)
            sum--;
    }
    for(int i=1;i<=sum;i++)
    {
        mp.clear();
        for(int j=1;j<=n;j++)
        {
            if(k[j])
            {
                if(!mp[b[i][j]])
                {
                    mp[b[i][j]]=1;
                    mp1[b[i][j]]++;
                }
            }
        }
    }
    int ans=0;
    for(char i='a';i<='z';i++)
    {
        if(mp1[i]==sum)
            ans++;
    }
    cout<<ans<<endl;
}

image-20210209215816411

题解

将u替换为oo,kh替换为h,然后找相同的字符串即可。

代码
#include <stdio.h>
#include <math.h>
#include <bits/stdc++.h>
using namespace std;
char a[500][500]={0};
int ans[500]={0};
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",a[i]+1);
    }
    for(int i=1;i<=n;i++)
    {
        stack<char>s;
        for(int j=1;a[i][j];j++)
        {
            if(a[i][j]=='u')
            {
                s.push('o');
                s.push('o');
            }
            else if(a[i][j]=='h')
            {
                while(!s.empty()&&s.top()=='k')
                    s.pop();
                s.push('h');
            }
            else
            {
                s.push(a[i][j]);
            }
        }
        int sum=0;
        while(!s.empty())
        {
            a[i][++sum]=s.top();
            s.pop();
        }
        a[i][++sum]='\0';
    }
    int ans1=0;
    for(int i=1;i<=n;i++)
    {
        if(ans[i])
            continue;
        for(int j=i+1;j<=n;j++)
        {
            if(strcmp(a[i]+1,a[j]+1)==0)
            {
                ans[j]=1;
                ans1++;
            }
        }
    }
    cout<<n-ans1<<endl;
}

image-20210209215948945

题解

找最大相同长度的回文字符串,可以发现构造 abcba 这种字符串(两边为能够匹配的字母,中间为不能匹配的)能够最小程度的减少块数,提高长度,用堆栈来模拟这个过程即可。

代码
#include <stdio.h>
#include <math.h>
#include <bits/stdc++.h>
using namespace std;
char a[400500]={0};
map<char,int>mp;
stack<char>s1,s2;
queue<char>que2;
int main()
{
    int n;
    scanf("%d",&n);
    scanf("%s",a+1);
    for(int i=1;i<=n;i++)
        mp[a[i]]++;
    for(char i='a';i<='z';i++)
    {
        if(mp[i]%2==1)
            que2.push(i);
        for(int j=1;j<=mp[i]/2;j++)
        {
            s1.push(i);
            s2.push(i);
        }
    }
    for(char i='0';i<='9';i++)
    {
        if(mp[i]%2==1)
            que2.push(i);
        for(int j=1;j<=mp[i]/2;j++)
        {
            s1.push(i);
            s2.push(i);
        }
    }
    for(char i='A';i<='Z';i++)
    {
        if(mp[i]%2==1)
            que2.push(i);
        for(int j=1;j<=mp[i]/2;j++)
        {
            s1.push(i);
            s2.push(i);
        }
    }
    if(que2.size()==0)
    {
        printf("%d\n",1);
        stack<char>s;
        while(!s1.empty())
            s.push(s1.top()),s1.pop();
        while(!s.empty())
            printf("%c",s.top()),s.pop();
        while(!s2.empty())
            printf("%c",s2.top()),s2.pop();
    }
    else
    {
        while(s1.size()%que2.size()!=0)
        {
            que2.push(s1.top());
            s1.pop();
            que2.push(s2.top());
            s2.pop();
        }
        printf("%d\n",que2.size());
        int size1=s1.size()/que2.size();
        while(!que2.empty())
        {
            stack<char>s;
            for(int i=0;i<size1;i++)
                s.push(s1.top()),s1.pop();
            while(!s.empty())
                printf("%c",s.top()),s.pop();
            printf("%c",que2.front()),que2.pop();
            for(int i=0;i<size1;i++)
                printf("%c",s2.top()),s2.pop();
            printf(" ");
        }
    }
}

image-20210209220611479

题解

二分最大差值,然后用dp来进行check()

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[300500]={0};
int dp[300500]={0};
int n,m;
int check(ll k)
{
    for(int i=1;i<=n;i++)
        dp[i]=0;
    dp[0]=1;
    int last=1;
    for(int i=1;i<=n;i++)
    {
        while(a[i]-a[last]>k)
            last++;
        for(int j=last;j+m<=i+1;j++)
        {
            if(dp[j-1])
            {
                dp[i]=1;
                break;
            }
            else
            {
                last++;
            }
        }
    }
    return dp[n];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    ll l=0,r=2e9;
    while(l<r)
    {
        ll mid=(l+r)/2;
        if(check(mid))
            r=mid;
        else
            l=mid+1;
    }
    cout<<l<<endl;
}