Codeforces Round #690 (Div. 3)(A->F)(F二分)

A:http://codeforces.com/contest/1462/problem/A

#include<iostream>
#include<cstring>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=2e4+10;
const int inf=99999999;
int a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        int cnt=0;
        int l=1;
        int ok=0;
        int md=n-1;
        while(1)
        {
            if(cnt==n)
                break;
            if(!ok)
            {
                cout<<a[l]<<" ";
                l=l+md;
                md--;
                ok=1;
            }
            else
            {
                cout<<a[l]<<" ";
                l=l-md;
                md--;
                ok=0;
            }
            cnt++;
        }
        cout<<endl;
    }
}

B:http://codeforces.com/contest/1462/problem/B

题意:

给定一个字符串,能否最多删除一段连续的一段使得剩下的为“2020”

解析:

无非就六种情况,直接列一遍就好了

#include<iostream>
#include<cstring>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=2e4+10;
const int inf=99999999;
int a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        string s;
        cin>>s;
        int le=s.length();
        if(s=="2020")
        {
            cout<<"YES"<<endl;
        }
        else
        {
            if(s[0]=='2'&&s[1]=='0'&&s[2]=='2'&&s[3]=='0')
            {
                cout<<"YES"<<endl;
            }
            else if(s[0]=='2'&&s[1]=='0'&&s[2]=='2'&&s[le-1]=='0')
            {
                cout<<"YES"<<endl;
            }
            else if(s[0]=='2'&&s[1]=='0'&&s[le-2]=='2'&&s[le-1]=='0')
            {
                cout<<"YES"<<endl;
            }
            else if(s[0]=='2'&&s[le-3]=='0'&&s[le-2]=='2'&&s[le-1]=='0')
            {
                cout<<"YES"<<endl;
            }
            else if(s[le-4]=='2'&&s[le-3]=='0'&&s[le-2]=='2'&&s[le-1]=='0')
            {
                cout<<"YES"<<endl;
            }
            else 
                cout<<"NO"<<endl;
        }
    }
}

C:http://codeforces.com/contest/1462/problem/C

题意:

输出最小的数位和等于x并且各个数位都不一样的值

解析:

在纸上写了一下,发现每一个存在的答案,都是从个位开始,数字越来越小。所以从9开始枚举即可。

#include<iostream>
#include<cstring>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=2e4+10;
const int inf=99999999;
int a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        if(n<=9)
        {
            cout<<n<<endl;continue;
        }
        if(n>45)
        {
            cout<<"-1"<<endl;continue;
        }
        int sum=0;
        int num[111];
        int tot=0,ok=0;
        int all=n;
        for(int i=9;i>=1;i--)
        {
            if(sum+i>n)
                continue;
            sum+=i;
            num[tot++]=i;
            if(sum==n)
            {
                ok=1;break;
            }
        }
        if(ok)
        {
            for(int i=tot-1;i>=0;i--)
                cout<<num[i];
            cout<<endl;
        }
        else
            cout<<"-1"<<endl;
    }
}

D:http://codeforces.com/contest/1462/problem/D

题意:

给出一个序列,每个数可以与左或右合并,这算一个操作。求使得所有数相同的最少操作数。

解析:

其实所谓所有数相同,就是把整个原数分成几份,每一份加和相等。

所以先求出总和sum,枚举它的因子x,求一下每份和为x  , sum / x的所需操作数,求个最小值即可。

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=3e3+10;
const int inf=99999999;
int a[maxn];
int n;
ll num[maxn];
ll sum=0;
int ac(int x)
{
    int all=sum/x;
    int ans=0;
    int cnt=0;
    int ok = 0 ;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>x)
            return -1;
        if(a[i]==x&&ans<x&&ans>0)
            return -1;
        if(ans+a[i]==x)
        {
            if(ans>0)
                cnt++;
            ans=0;    
        }
        else if(ans+a[i]<x)
        {
            if(ans>0)
            cnt++;
            ans+=a[i];
            
        }
        else
        {
            return -1;
        }
    }
    return cnt;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        cin>>n;
        sum = 0 ;
        for(int i=1;i<=n;i++)
            cin>>a[i],sum+=a[i];
        int no=0;
        for(int i=1;i<n;i++)
        {
            if(a[i]!=a[i+1])
            {
                no=1;break;
            }
        }
        if(!no)
        {
            cout<<"0"<<endl;continue;
        }
//        cout<<ac(sum/2)<<endl;
        int ok = 0;
        int an=inf;
        for(int i=2;i*i<=sum;i++)
        {
            if(sum%i==0)
            {
                int md1=ac(i);
                int md2=ac(sum/i);
                if(md1!=-1)
                {
                    an=min(an,md1);
                //    cout<<i<<"--1"<<endl;
                    ok=1;
                }
                if(md2!=-1)
                {
                    an=min(an,md2);
                //    cout<<i<<"--2"<<endl;
                    ok=1;
                }    
            }
        }
        if(!ok)    
            cout<<n-1<<endl;//不存在,那么全合并即可
        else
            cout<<an<<endl;
    }
}

E1:http://codeforces.com/contest/1462/problem/E1

题意:

求有多少组ai,aj,az,max(ai,aj,az)-min(ai,aj,az)<=2

解析:

由于这三个数并不需要挨着,所以顺序无所谓。那么可以先从小到大排个序。

枚举最小值ai,向右找到第一个aj-ai>2的位置,那么i~j之间的数字随便选两个和ai组合就是一组答案,那么答案就是C(j-i-1,2),累加即可。

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int inf=99999999;
int a[maxn];
int n;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        sort(a+1,a+1+n);
        ll sum = 0 ;
        int r=2;
        for(int i=1;i<=n;i++)
        {
            while(a[r]-a[i]<=2&&r<=n)
                r++;
            ll cnt=(r-i-1);
            if(cnt>=2)
                sum+=cnt*(cnt-1)/2;
            
        }
        cout<<sum<<endl;
    }
}

E2:http://codeforces.com/contest/1462/problem/E2

与E1不同的是,所选数目以及最大差值可以自定义。

与E1思路相同,只是难点在求组合数这边。考虑m只有100,那么提前预处理一下组合数即可。

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int inf=99999999;
const int mod=1e9+7;
int a[maxn];
int n,m,k;
int c[maxn][130];
void init()
{
    
    c[0][0]=1;
    c[1][0]=1;c[1][1]=1;
    for(int i=2;i<maxn;i++)
    {
        for(int j=0;j<=105&&j<=i;j++)
        {
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
}
int main()
{
    int t;    
    init();
    scanf("%d",&t);
    while(t--)
    {
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        sort(a+1,a+1+n);
        ll sum=0;
        int r=1;
        for(int i=1;i<=n;i++)
        {
            while(a[r]-a[i]<=k&&r<=n)
                r++;            
            ll cnt=(r-i-1);
            if(cnt>=m-1)
            {
                sum=(sum+c[cnt][m-1])%mod;
            }
        }
        cout<<sum<<endl;
    }
}

F:http://codeforces.com/contest/1462/problem/F

题意:

给你n个线段,代表线段的左右端点,问最少删几条线段,使得剩下当中存在一个线段与所有剩下的所有线段都有交集。

解析:

考虑枚举每一条线段,求以此线段与所有线段都有交集,需要删除的线段数。

那么对于此线段[L,R],右端点小于L的,与它无交集,需要全删掉。同理左端点大于R的线段,也需要都删掉。

那么剩下的问题,就是需要删几个了。

预存一下所有的L,R,放到x[],y[]里面。对它们进行从小到大的排序。

对于当前枚举到的[L,R],求小于L的右端点不好求,那就先求>=L的,就是:lower_bound(y+1,y+1+n,a[i])-y;  再减1,就是小于L的了:lower_bound(y+1,y+1+n,a[i])-y-1;

然后求大于R的左端点,n-(upper_bound(x+1,x+1+n,b[i])-x)+1;

加起来,每次取最小即可。

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdio>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int inf=99999999;
const int mod=1e9+7;
int a[maxn],b[maxn],x[maxn],y[maxn];
int main()
{
    int t;    
    scanf("%d",&t);
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i]>>b[i];
            x[i]=a[i];
            y[i]=b[i];
        }
        sort(x+1,x+1+n);
        sort(y+1,y+1+n);
        ll minn = inf;
        for(int i=1;i<=n;i++)
        {
            ll l=lower_bound(y+1,y+1+n,a[i])-y-1;
            ll r=n-(upper_bound(x+1,x+1+n,b[i])-x)+1;
            minn=min(minn,l+r);
        }
        cout<<minn<<endl;
    }
}
原文地址:https://www.cnblogs.com/liyexin/p/14152120.html