codeforces 1257 总结

C
给出n,再给长度为n的一组小于等于n的数,问具有重复数的最小连续子串的长度是多少。

思路:有选择的排序。

#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
//int a[200005];
struct node
{
    int index;
    int val;
}a[200005];
bool cmp(node p1,node p2)
{
    if(p1.val==p2.val)
        return p1.index<p2.index;
    else return p1.val<p2.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].val);
           a[i].index=i;
       }
       sort(a+1,a+1+n,cmp);
      /* for(int i=1;i<=n;i++)
        cout<<a[i].val<<" "<<a[i].index<<endl;*/
       int ans=1e6+10;
       for(int i=1;i<=n-1;i++)
       {
           if(a[i].val==a[i+1].val)
           {
              // cout<<tt<<endl;
                  ans=min(ans,a[i+1].index-a[i].index+1);
                 // cout<<ans<<endl;
           }
       }
       if(ans<1e6) printf("%d\n",ans);
       else printf("-1\n");
   }
   return 0;
}

D
有n个怪物,m个英雄,每天可派出一个英雄去杀怪物,每个英雄每天最多杀ai个怪物,若遇到力量值大于英雄的怪物,英雄撤退,英雄可以无限次使用,问最少需要多少天杀光或者是不可能完成。

思路:由于可以无限次使用,那么,忍耐值大的留下,忍耐值相同,力量值大的留下。预处理出一个数组,专门存放力量值最大,忍耐值最好的英雄,然后定义两个指针,一个指向怪物,一个指向英雄,模拟情况。

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const int N=2e5+5;
int a[N],b[N];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1; i<=n; i++)
        {
            cin>>a[i];
        }
        int x,y;
        int m;
        for(int i=1;i<=n+4;i++)
            b[i]=0;
        cin>>m;
        for(int i=1; i<=m; i++)
        {
            cin>>x>>y;
            b[y]=max(x,b[y]);
        }
        for(int i=n; i>=1; i--)
        {
            b[i]=max(b[i],b[i+1]);
        }
        int cnt=0;
        int pos1=1,pos2=1;
        int tt=0;
        bool flag=true;
        while(1)
        {
            if(pos1>n) break;
            cnt++;
            tt=0;
            while(1)
            {
                tt=max(tt,a[pos1]);
                if(tt>b[pos2])
                {
                    pos2=1;
                    break;
                }
                pos1++;
                pos2++;
                if(pos1>n) break;
            }
            if(pos1>n) break;
            if(tt>b[1])
            {
                flag=false;
                break;
            }
        }
        if(flag)
        {
            cout<<cnt<<endl;
        }
        else cout<<"-1"<<endl;
    }
    return 0;
}

E
给出三堆数, 这三堆数由1-n组成,无重复数字,把其中一堆数的一个数给另一堆数花费为1,问要使第一堆是前缀,第三堆是后缀,第二堆是中间的最小花费是多少?这里可以使任何两堆数的个数为零。
思路:
第一感觉是dp应该能解决,但是,想不出来。
看网上一个巧妙的dp方法,设dp[i][k]表示第i个数分配完以后,若i分配给第k堆得最小花费。
dp[i][k]=min(d[i][k],dp[i-1][j]+1(如果当前这个数不在j堆得话))其中j要小于k.

文章链接:https://blog.csdn.net/weixin_43562213/article/details/103168350

F
给一组数,问是否存在一个数,使得这组数的每一个数亦或这个数后,得到的新的一组数的每一个数的二进制表示的1的个数相等。范围 2^30之内。

思路:看题解的意思是说把2^30拆成两个部分,2的15次方的情况记录下来,两个二的15次方就能拼成2的30次方的情况,通过查哈希表看是否能找到所包含的情况,然后输出。虽说这么说是行,但是题解里的位运算让人头痛,里面位运算的作用还没太搞清楚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值