codeforces 1251 总结

A
键盘按钮有的坏了,坏了的按一下出两个字母,现在给出打印好的字符串,判断好的按钮有哪些,按字典序输出。
思路:暴力求解

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
int main()
{
    int t;
    scanf("%d",&t);
    char ch[505];
    while(t--)
    {
        scanf("%s",ch+1);
        int len=strlen(ch+1);
        int cnt=1;
        int pos=1;
        set<char>p;
       while(1)
       {
           cnt=1;
           while(1)
           {
               if(ch[pos]==ch[pos+1])
               {
                   cnt++;
                   pos++;
                   continue;
               }
               else break;
               if(pos>len) break;
           }
           if(cnt&1)
           {
               p.insert(ch[pos]);
               pos++;
           }
           else pos++;
           if(pos>len) break;
       }
       if((int)p.size()>0)
       {
           set<char>::iterator it;
           for(it=p.begin();it!=p.end();it++)
            printf("%c",(*it));
       }
       printf("\n");
    }
    return 0;
}

B
给n个字符串,由01组成,每次操作可任意选两个或一个字符串,若选两个,可相互交换任意位置上的元素,在两个字符串之间,若选一个,可以任意交换这个字符串上的元素。问最多能得到多少回文字符串。
思路:只有存在偶数长度的字符串且这个字符串由奇数个1奇数个0的时候,如果没有奇数长度的字符串给他搭配,那么他将变不成回文,如果存在奇数长度的字符串,那么这个字符串可以反复使用,来使其他变回文,若没有奇数长度的串,且0的个数为奇数,1的个数为技术,那么必有一个串符合最开始描述的那种变不成的情况。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        char s[55];
        int jud=0;
        int cnt[2]={0};
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            int len=strlen(s);
            if(len&1) jud=1;
            for(int j=0;j<len;j++)
            {
                cnt[s[j]-'0']++;
            }
        }
        if(cnt[0]%2&&cnt[1]%2&&jud==0)
            n--;
        printf("%d\n",n);

    }
    return 0;
}

C
给一串字符串,看成一个数,每次操作可交换相邻的奇偶不同的两个元素,问最小字典序的串是什么。
思路:这道题我蠢到用模拟去做,哎。其实,奇偶不同不能换,那么奇数与奇数相对位置不变,偶数也这样,分别放两个组里,然后来回比较大小。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[300005];
char ch1[300005];
char ch2[300005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s+1);
        int len=strlen(s+1);
        int pos1=0,pos2=0;
        for(int i=1;i<=len;i++)
        {
            if((s[i]-'0')&1)
                ch1[++pos1]=s[i];
            else ch2[++pos2]=s[i];
        }
        int p1=1;
        int p2=1;
        while(p1<=pos1||p2<=pos2)
        {
            if(ch1[p1]<ch2[p2]&&p1<=pos1&&p2<=pos2)
            {
                printf("%c",ch1[p1]);
                p1++;
            }
            else if(ch1[p1]>ch2[p2]&&p1<=pos1&&p2<=pos2)
            {
                printf("%c",ch2[p2]);
                p2++;
            }
            else if(p1>pos1)
            {
                printf("%c",ch2[p2]);
                p2++;
            }
            else if(p2>pos2)
            {
                printf("%c",ch1[p1]);
                p1++;
            }
        }
        printf("\n");

    }
    return 0;
}

D
给n个范围,(l,r),给一个数s,把这个数拆成n个数,且每个数都符合各自的范围,s可以不用完,问这n个数的最大中位数是什么。
思路:二分中位数,看能否满足中位数的条件,并且判断和值是否超过了s。进而确定二分区间。`

#include <iostream>
#include<cstdio>
#include<cstring>
#include<utility>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2e5+5;
pair<ll,ll>a[N];
ll s;
int n;
int num;
bool jud(ll mid)
{
    ll cost=0;
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        if(a[i].first>=mid)
        {
            cnt++;
        }
        else if(a[i].second>=mid)
        {
            cost=cost+mid-a[i].first;
            cnt++;
        }
        if(cost>s) return 0;
        if(cnt==num) return 1;
    }
    return 0;
}
int main()
{
   ios::sync_with_stdio(0);
   cin.tie(0);
   cout.tie(0);
   int t;
   cin>>t;
   while(t--)
   {
       cin>>n>>s;
       for(int i=0;i<n;i++)
        cin>>a[i].first>>a[i].second;
       sort(a,a+n,greater<pair<ll,ll>>());
       ll l=a[n/2].first;
       ll r=s;
       num=(n+1)/2;
       ll ans=0;
       for(int i=0;i<n;i++)
       {
           s=s-a[i].first;
       }
       while(l<=r)
       {
           ll mid=(l+r)>>1;
           if(jud(mid))
           {
               l=mid+1;
               ans=mid;
           }
           else r=mid-1;
       }
       cout<<ans<<endl;
   }
   return 0;
}

E
有n个人,每人一张选票,若使得他投给你,可以花pi的钱收买,若有mi个人投了你,则第i个人也会投你,问你要让所有人投你,最少花多少钱。
思路:
只有先收买m值大的,然后m值小的才有可能不花钱,若几个人的m值一样,就买小的那个,但要保证,买完后要使没买的那几个免费投你。
那么,也就是说,有4个人m值为7,一共10个人,那么你要买一个人,这样的话剩下的那三个人就能免费投你,因为已经有七个人投了你。
哎,绕了一晚上。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#define ll long long
using namespace std;
const int N=5005;
vector<ll> v[N];
int main()
{
    int t;
    scanf("%d",&t);
    int n;
    while(t--)
    {
       priority_queue<ll,vector<ll>,greater<ll> >q;
       scanf("%d",&n);
       for(int i=0;i<=n;i++) v[i].clear();
       int m;ll p;
       for(int i=1;i<=n;i++)
       {
           scanf("%d%lld",&m,&p);
           v[m].push_back(p);
       }
       ll res=0;
       for(int i=n-1;i>=0;i--)
       {
           for(int j=0;j<(int)v[i].size();j++)
           {
               q.push(v[i][j]);
           }
           while(q.size()>n-i)
           {
               res=res+q.top();
               q.pop();
           }
       }
       printf("%lld\n",res);
    }
    return 0;
}

F
有a个白木板,b个红木板,长短不一,要求红的长度最长处于中心位置且只有一个,左边的单调递增,右边的单调递减,左右都是白的。木板宽度为1,给出木板周长,有多少种木板的组合方案。
思路:题解里的dp方程比较好理解,但是NTT头一次见。题解里把dp和NTT衔接,衔接的很巧妙,NTT的模板没搞熟悉,还要再看看,不过倒是可以直接保存起来,拷贝直接用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值