codeforces edu 67 A-E

A Stickers and Toys
思路:水题,保证取到就是在max(a,b)中然后减去两者都有的那部分-(a+b-n)再+1无论如何都可以满足

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long 

using namespace std;

int main()
{
   ll t,n,s,q;
   scanf("%lld",&q);
   while(q--)
   {
      scanf("%lld%lld%lld",&n,&s,&t);
      printf("%lld",max(s,t)-(s+t-n)+1);
   }
   return 0; 
}

B.
思路:预先开个数组存储每个字母第i次出现的位置,然后扫的时候不断相应取max即可 o(n)可过

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#define ll long long 
using namespace std;
vector<int>v[27];
int a[27];
int main()
{
    int n,m,q;
    string s;
    cin>>n;
    cin>>s;
    for(int i=0;i<s.size();++i)
    {
       v[s[i]-'a'].push_back(i); 
    }
    cin>>q;
    while(q--)
    {
       memset(a,0,sizeof(a));
       string x;
       cin>>x;
       int ans=0;
       for(int i=0;i<x.size();++i)
       {
          ans=max(ans,v[x[i]-'a'][a[x[i]-'a']]+1);
          a[x[i]-'a']++;
       } 
       cout<<ans<<"\n";
    }
    return 0;
}

C.
构造题,首先考虑构造数组a[i]=(a[i]<=a[i+1]),然后扫一遍0的,不存在的情况就是他的区间中a[i]没有一个0,a[i]=1时就和前面的一样,否则就-1,注意到数字一定要>=1,所以第一位从n开始构造

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long 
const int maxn=1010;
 using namespace std;
int is[maxn];
int t[maxn],l[maxn],r[maxn];
 
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;++i)
    {
        scanf("%d%d%d",&t[i],&l[i],&r[i]);
        l[i]--,r[i]--;
        if(t[i]==1)
        {
            for(int j=l[i];j<r[i];++j)
                is[j]=1;
        }
    }
   for(int i=0;i<m;++i)
    {
        int flag=0;
        if(!t[i])
        {
            for(int j=l[i];j<r[i];++j)
                if(!is[j])
                {
                    flag=1;
                    break;
                }
            if(!flag)
            {
                puts("NO");
                return 0;
            }
        }
    }
    puts("YES");
    int ans=n;
    printf("%d ",ans);
    for(int i=1;i<n;++i)
    {
        if(is[i-1])
            printf("%d ",ans);
        else
            printf("%d ",--ans);
    }
   cout<<endl;
}

D.
思路:一次操作等同于左边比右边大的话不断两两交换,所以a[i]能到最前面的条件(指前面的最前面已经满足了)是(1,n)中它为最小(前面最小的被打过标记),所以建个线段树,从前往后扫,用队列记录出现位置,一旦判断过,就打个最大值标记

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long 
#define ls rt<<1
#define rs rt<<1|1
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=3e5+5;
int tr[maxn<<2];
queue<int>q[maxn];
int a[maxn],b[maxn];
const int inf=0x3f3f3f3f;
void build(int rt,int l,int r)
{
   if(l==r)
   {
      tr[rt]=a[l];
      q[a[l]].push(l);
      return; 
   } 
   int mid=l+r>>1;
   build(lson);
   build(rson);
   tr[rt]=min(tr[ls],tr[rs]);
}
void update(int rt,int l,int r,int x,int k)
{
   if(l==r)
   {
      tr[rt]=k;
      return; 
   } 
   int mid=l+r>>1;
   if(x<=mid)update(lson,x,k);
   else update(rson,x,k);
   tr[rt]=min(tr[ls],tr[rs]);
}
int query(int rt,int l,int r,int x,int y)
{
   if(x<=l&&r<=y)
   {
      return tr[rt]; 
   } 
   int mid=l+r>>1;
   int val=(1<<30);
   if(x<=mid)val=min(val,query(lson,x,y));
   if(y>mid)val=min(val,query(rson,x,y));
   return val;
}
int main()
{
   int t;
   scanf("%d",&t);
   while(t--)
   {
      int n;
      scanf("%d",&n);
      for(int i=1;i<=n;++i)
      {
         scanf("%d",&a[i]);
         while(!q[a[i]].empty())    
             q[a[i]].pop();
         
      } 
      build(1,1,n);
      for(int i=1;i<=n;++i)
          scanf("%d",&b[i]);
      int flag=1;
      for(int i=1;i<=n;++i)
        {
           int k;
           if(!q[b[i]].empty())
           {
              k=q[b[i]].front();
              q[b[i]].pop(); 
           } 
           else 
		   { 
                flag=0;
                break;
           }
           int minn=query(1,1,n,1,k);
           if(minn!=b[i])
           {
              flag=0;
              break; 
           }
           else update(1,1,n,k,inf);
        }
      if(flag)puts("YES");
      else puts("NO");
   }
   return 0; 
}

E.
二次扫描+换根法板子题
可以发现一旦根确定了,答案也是确定的,所以只要判断每个根即可,而且发现答案是各个结点子树大小之和
直接两次dfs,第一次处理所有结点的子树大小,第二次换根的时候只会影响到换的两个结点的子树的大小来影响答案,具体看代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long 
const int maxn=2e5+10;
using namespace std;
int head[maxn],next1[maxn<<1],ver[maxn<<1],tot=0;
int size[maxn],n;
ll ans;
void add(int x,int y)
{
   ver[++tot]=y,next1[tot]=head[x],head[x]=tot; 
}
void dfs(int now,int fa)
{ 
    size[now]=1;
    for(int i=head[now];i;i=next1[i])
    {
        int y=ver[i];
        if(y==fa)continue;
          dfs(ver[i],now);
          size[now]+=size[y]; 
    }
    ans+=size[now];
}
void dfs2(int now,int fa,ll num)
{
   ans=max(ans,num);
   for(int i=head[now];i;i=next1[i])
   {
       if(ver[i]==fa)continue;
       dfs2(ver[i],now,num+n-2*size[ver[i]]); 
   } 
}
int main()
{
   scanf("%d",&n);
   for(int i=1;i<n;++i)
   {
      int a,b;
      scanf("%d%d",&a,&b);
      add(a,b);
      add(b,a); 
   }
   ans=0;
   dfs(1,-1);
   dfs2(1,-1,ans);
   printf("%lld\n",ans);
   return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值