cf985

題目鏈接:http://codeforces.com/contest/985

A:

暴力題吧,只需要在把黑色和白色的值都算一遍,最後取兩種情況的min就可以了。


B:

模擬題,只需要每次枚舉那個開關不動即可。


C:

只需要sort一下,想一下如何選取即可。舉個栗子吧:

其中劃豎線的地方就是臨界點(剛好滿足題意)

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll a[maxn];
bool vis[maxn];
bool cmp(ll a,ll b)
{
    return a<b;
}
int main()
{
    int n,k;
    ll l;
    scanf("%d%d%I64d",&n,&k,&l);
    for(int i=1;i<=n*k;++i)
    {
        scanf("%I64d",&a[i]);
    }
    sort(a+1,a+1+n*k);

    ll ans=0;
    int cnt=0;
    for(int i=n*k-k+1;i>=1;i--)
    {
        if(a[i]-a[1]>l) continue;
        if(i<n) break;

        cnt=i;
        break;
    }
    //printf("%d %d\n",n*k-k+1,cnt);
    if(cnt)
    {
        memset(vis,0,sizeof(vis));
        int flag=0,num=0;
        for(int i=cnt;i>=1;i--)
        {
            if( (i-1)%k==0)
            {
                flag=i;
                break;
            }
        }
        //printf("%d %d\n",cnt,flag);


        for(int i=1;i<=n*k;i+=k)
        {
            if(i>flag) break;
            vis[i]=1;
            ans+=a[i];
            num++;
        }

        for(int i=cnt;i>=1;--i)
        {
            if(num==n) break;
            if(vis[i]) continue;
            vis[i]=1;
            ans+=a[i];
            num++;
        }

    }
    printf("%I64d\n",ans);
    return 0;
}
/*
4 5 3
1 1 2 2 1 2 2 3 3 4 4 4 5 5 5 5 5 5 6 6
*/

D:

二分一下,堆的最高值即可! 構造很關鍵

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
ll n,h,ans=0x7f7f7f7f7f7f7f7f;
bool check(ll mid)
{
    ll ret,need;
    if(mid>h)
    {
        need = ll(1.0*(h+mid)*(mid-h+1)/2+1.0*(mid-1)*mid/2);
        ret= mid-h+mid;
    }
    else
    {
        need=ll(1.0*mid*(mid+1)/2);
        ret=mid;
    }
    if(need>n) return 0;
    ll last=n-need;
    ret += last/mid+(last%mid>0);
    if(ret<=ans)
    {
        ans=ret;
        return 1;
    }
    return 0;
}
int main()
{

    scanf("%I64d%I64d",&n,&h);
    ll l=1 , r=int(2e9)+7,mid;
    while(l<=r)
    {
        mid= (l + r)>>1;
        if(check(mid)) l=mid+1;
        else r=mid-1;
    }
    printf("%I64d\n",ans);
    return 0;
}

E:

dp題吧,

dp[i]=a, 代表包含i的這堆的起始位置是誰。

轉移就是

        int pre=dp[i-m+1];
        if(a[i]-a[pre]<=k) dp[i+1]=i+1;
        else dp[i+1]=dp[i];

如果滿足題意,那麼下一個位置就可以做開頭。


#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+100;
int a[maxn];
bool cmp(int a,int b)
{
    return a<b;
}
int dp[maxn];
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=m;++i) dp[i]=1;
    for(int i=m;i<=n;++i)
    {
        int pre=dp[i-m+1];
        if(a[i]-a[pre]<=k) dp[i+1]=i+1;
        else dp[i+1]=dp[i];
    }
    if(dp[n+1]==n+1) printf("YES\n");
    else printf("NO\n");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章