每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

Codeforces Round #768 (Div. 2)C ,D

Codeforces Round #768 (Div. 2)C ,D

C

C

这一道题的大意是从0到n-1,(n一定是2的x次方),我需要找n/2对数对,使得每一个数对(x,y),x&y的和要等于k(k<=n-1)

我一开始是没什么思路的,直到我看了大佬的讲解,ε=(´ο`*)))唉

下面是我的理解

n=8时

000和111(0和7)

001和110(1和6)

010和101(2和5)

011和100(3和4)

这些对进行&的值都是0,而且每一个都是i和n-i-1,所以当k=0时,答案就是每一个(i,n-i-1)

又因为1111&x=x

所以当k<n-1我们可以让k和n-1配对,那么而原本要和k配对的n-k-1和原本要和n-1配对的0就配对(刚好0&n-k-1=0,其他的也一定会是0)

而当k=n-1时n-1是最大的,而&一定会比n-1少,那么我们必须由两个部分来组成,1和n-2

那么我们可以这样

 cout<<n-2<<" "<<n-1<<'\n';//这个是n-2,还剩1(下面配对),0没有配对对象
 cout<<1<<" "<<3<<'\n';//这个是1,还剩n-2(上面已经配对),n-4没有配对对象
 cout<<0<<" "<<n-4<<'\n';//0和n-4配对

其他的按照原来的配对方式来

#include <iostream>
#include <vector>
using namespace std;
const int maxn=2e5+10;
int t,n,k;
void solve()
{
    cin>>n>>k;
    if (n==4&&k==3)
    {
        cout<<-1<<'\n';
        return ;
    }
    if (k==0)
    {
        for (int i=0;i<n/2;i++)
        {
            cout<<i<<" "<<n-i-1<<'\n';
        }
    }
    else if (k<n-1)
    {
        cout<<0<<" "<<n-k-1<<'\n';//这一个是把原来和k配对,和n-1配对的来配对,刚好交换了原来0和n-1的配对对象
        cout<<k<<" "<<n-1<<'\n';//k&(n-1)=k
        for (int i=1;i<n/2;i++)
        {
            if (i!=k&&(n-i-1)!=k)
            {
                cout<<i<<" "<<n-i-1<<'\n';
            }
        }
    }
    else if (k==n-1)//k=n-1,n-1是最大的,而&一定会比n-1少,那么我们必须由两个部分来组成,1和n-2
    {
        cout<<n-2<<" "<<n-1<<'\n';//这个是n-2,还剩1(下面配对),0没有配对对象
        cout<<1<<" "<<3<<'\n';//这个是1,还剩n-2(上面已经配对),n-4没有配对对象
        cout<<0<<" "<<n-4<<'\n';//0和n-4配对
        cout<<2<<" "<<n-3<<'\n';
        for (int i=4;i<n/2;i++)
        {
            cout<<i<<" "<<n-i-1<<'\n';
        }
    }
    return ;
}
int main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

D

D

这题的大意是有一个数组,我们需要把这个数组分成k份,而我们则需要得到一个范围[x,y],只要每一份里面的数其中在这一个范围里的数量大于不在这个范围的数量就可以了,我们需要输出min(y-x)的符号以上条件的x,y然后再输出每一份的l,r

假如p是在[x,y]里的数量,q是不在[x,y]里的数量,那么对于一份,就是p-q>=1,对于k组(n个所有的数),那么就是p-q>=k,而我们要求这n个数里在[x,y]范围的数量,我这里用到了前缀和,而对于寻找min(y-x),这里用到了二分,这样求出了min(y-x),然后我们只需要求出k-1份l,r最后一份就是k-1的r+1到n

对于每一份的l,r的寻找,我们只需要模拟,一旦p>q,就把此时的l,r存进去,然后更新l

具体看代码

对于那一个求前缀和来判断这一对[x,y]是否符合条件,我是觉得太妙了,好聪明的想法

#include <iostream>
#include<vector>
// #include <pair>
using namespace std;
const int maxn=2e5+10;
int n,k,a[maxn],sum[maxn];
pair<int,int>b[maxn];
int t;
inline bool check(int x,int y)
{
    int d=sum[y]-sum[x-1];
    if (2*d-n>=k) return true;//d-(n-d)>=k
    return false;
}
void solve()
{
    cin>>n>>k;
    sum[0]=0;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]=0;
    }
    for (int i=1;i<=n;i++)
    {
        sum[a[i]]++;
    }
    for (int i=1;i<=n;i++)
    {
        sum[i]=sum[i-1]+sum[i];
    }
    pair<int,int>ans;
    ans={1,n};
    for (int x=1;x<=n;x++)
    {
        int l=x,r=n;
        int ansr=r;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (check(x,mid))
            {
                r=mid-1;
                ansr=mid;
            }
            else l=mid+1;
        }
        if (check(x,ansr))
        {
            int len=ansr-x;
            int lenn=ans.second-ans.first;
            if (len<lenn)
            {
                ans={x,ansr};
            }
        }
    }
    int cnt=0;
    int x=ans.first,y=ans.second;
    int l=1,sum=0;
    for (int i=1;i<=n;i++)
    {
        if (a[i]>=x&&a[i]<=y) sum++;
        else sum--;
        if (sum>0)
        {
            b[++cnt]={l,i};
            sum=0,l=i+1;
            if (cnt==k-1) break;
        }
    }
    cout<<x<<" "<<y<<'\n';
    for (int i=1;i<k;i++)
    {
        cout<<b[i].first<<" "<<b[i].second<<'\n';
    }
    cout<<b[k-1].second+1<<" "<<n<<'\n';
    return ;
}
int main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}
posted @   righting  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示