codeforces 558c&558d&558e

558c题意:给出若干数,可对数进行操作(乘2或者除以2)。求最少的操作使得所有的数都相等。

以二进制的角度看这些数和操作,目标就是使得最后的二进制相等,也就是每个位置对应的数都相等,反观操作,乘上2相当于二进制左移动而且二进制中的1的个数不会减少,而除以2相当与二进制右移但是会造成二进制中的1的个数减少。。
那么,我们找出所有数的公共前缀,从第一个不为零的数开始。
如(001010)、(101000)、(001011),公共前缀就是101,那么将每个二进制中的101之后存在的1的往后移位消除多余的1(除法),知道消除多余的1即可。经过第一步之后生下来的二进制为:1010,101000,101前两个都不需要移动。没有没有多余的1
那么经过这一步之后每个二进制都是xxx101xxx…..的形式,那么接下来把所有的二进制101对齐即可。 how.
.将每个二进制的长度视为x轴上的点,其实就是找出一个点使得这个点到所有二进制代表的点的距离相等~其实就是找中位数。
这样就解决了

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define exp 1e-8
#define INF 0x3f3f3f3f
#define ll long long
#define mm(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
void bug(string st="bug")
{cout<<st<<endl;}
template<typename __ll>
inline void READ(__ll &m){
    __ll x=0,f=1;char ch=getchar();
    while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    m=x*f;
}
template<typename __ll>
inline void read(__ll &m){READ(m);}
template<typename __ll>
inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>
inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
int num[100010];
int two[100010][22];
int idx[100010];
int cnt[100010];
int main()
{
    int n;
    read(n);
    for1(i,n)read(num[i]);
    int minn=0;
    for1(i,n)  //找二进制
    {
        int tmp=num[i];
        cnt[i]=0;
        while(tmp)
        {
            two[i][++cnt[i]]=tmp%2;
            tmp/=2;
        }
    }
    int ccc=0;
    for(int j=0;j<=20;j++)  //找出前缀中一共有多少个1,,,不需要看0
    {
        int flag=1;
        if(cnt[1]-j<1)flag=0;
        if(flag==0)break;
        int tmp=two[1][cnt[1]-j];
        for(int i=2;i<=n;i++)
        {
            if(cnt[i]-j<1){flag=0;break;}
            if(two[i][cnt[i]-j]!=tmp)
                flag=0;
        }
        if(flag==0)break;
        minn+=tmp;
        if(j==20)
        {
            cout<<0<<endl;
            return 0;
        }

    }
    int ans=0;
    for1(i,n)
    {
        int tmp=minn;
        int first=-1;
        for(int j=20;j>=1;j--)
        {
            if(two[i][j]==1&&first==-1)first=j;
            tmp-=two[i][j];
            if(tmp==-1)  //将多余的1移除
            {
                ans+=j;  //需要移动这么多步
                idx[i]=first-j;
                break;
            }
        }
        if(tmp==0)
            idx[i]=first;
    }
    sort(idx+1,idx+1+n);
    int mid=idx[n/2+1];  //找出中位数
    for1(i,n) ans+=abs(idx[i]-mid);
    cout<<ans<<endl;
}

558d题意:给出若干数据,看数据是否矛盾,或者是否有多个出口。
数据有两种类型,一个是出口的若干区间,一个不是出口若干区间。
那么首先对是出口的若干区间操作合并求交集
如果合并不出一个合理的区间,那么Game cheated!。
如果有一个合理的区间,exit肯定在这个区间,设为区间A。
但还要根据第二种数据操作。
对不是出口的若干区间操作合并求并集
那么exit一定存在与这个并集的补集里,补集设为B,总集合为子叶
那么如果A与B没有交集,那么Game cheated!。
如果A与B有交集,但有若干个,Data not sufficient!
否则,只有一个exit

#include <algorithm>
#include <algorithm>
#include <iostream>
#include<string.h>
#include <fstream>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define exp 1e-8
#define fi first
#define se second
#define ll long long
#define INF 0x3f3f3f3f
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define bug printf("bug_here\n")
#define all(a) a.begin(),a.end()
#define mm(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
using namespace std;
template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;}
template<typename __ll>inline void read(__ll &m){READ(m);}
template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);}
template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; }
template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; }
template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; }
template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; }
template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; }
vector<pair<ll,int> >vec;
int main()
{
    int h,q;
    read(h,q);
    ll L=1,R;
    for1(i,h-1)L*=2LL;
    R=L*2LL-1;
    ll ansl=L,ansr=R;
    while(q--)
    {
        int i,ans;
        ll l,r;
        read(i),read(l,r),read(ans);
        int ret=h-i;for1(i,ret)l*=2LL;
        r++;for1(i,ret)r*=2LL;r--;
        if(ans==1)
        {
            rmax(ansl,l);
            rmin(ansr,r);
        }
        else vec.pb(mp(l,-1)),vec.pb(mp(r,1));
    }
    if(ansl>ansr){printf("Game cheated!\n");return 0;}
    vec.pb(mp(L-1,-1));vec.pb(mp(L-1,1));
    vec.pb(mp(R+1,-1));vec.pb(mp(R+1,1));
    sort(all(vec));
    int cnt=0;
    ll val=-1;bool many=0;
    for(int i=0;i<(int)vec.size()-1;i++)
    {
        cnt+=vec[i].se;
        if(cnt==0)
        {
            ll nl=vec[i].fi+1,nr=vec[i+1].fi-1;   //找出补集
            rmax(nl,ansl),rmin(nr,ansr);
            if(nl<nr)  //假设这个地方是有的
                many=1,val=nl;
            else if(nl==nr&&val!=-1)
                many=1,val=nl;
            else if(nl==nr&&val==-1)
                val=nl;
            //if(nl>nr) 假设没有~~~~
        }
    }
    if (val == -1)
        printf("Game cheated!\n");
    else if (many)
        printf("Data not sufficient!\n");
    else
        cout << val << endl;
}

558e
建立26个线段树,分别对应a–z 26个字母
每次修改[l,r]区间,则先通过26课线段树查询求出这个区间内的a–z分别有多少个。然后将26课线段树内的这一区间和置为0.最后根据顺序重新给26课线段树的这一区间赋值~。
这道题觉得和557c特别相像,数组大小为200,代价特别小,就好比这里的26棵线段树。200、26都很小。。乘入复杂度基本可以忽略。。这一小部分可以通过暴力求出来

#include <algorithm>
#include <algorithm>
#include <iostream>
#include<string.h>
#include <fstream>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define exp 1e-8
#define fi first
#define se second
#define ll long long
#define INF 0x3f3f3f3f
#define lson l,mid,rt<<1
#define pb(a) push_back(a)
#define rson mid+1,r,rt<<1|1
#define mp(a,b) make_pair(a,b)
#define all(a) a.begin(),a.end()
#define mm(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
#define repp(a,b,c)for(int a=b;a>=c;a--)///
using namespace std;
void bug(string m="here"){cout<<m<<endl;}
template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;}
template<typename __ll>inline void read(__ll &m){READ(m);}
template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);}
template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; }
template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; }
template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; }
template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; }
template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; }
const int maxn=100010;
struct Seg_TREE
{
    int sum[maxn<<2],cov[maxn<<2];
    void push_down(int l,int r,int rt)
    {
        if(cov[rt]!=-1)
        {
            int mid=l+r>>1;
            cov[rt<<1]=cov[rt<<1|1]=cov[rt];
            sum[rt<<1|1]=(r-mid)*cov[rt];
            sum[rt<<1]=(mid-l+1)*cov[rt];
            cov[rt]=-1;
        }
    }
    void push_up(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {

        sum[rt]=0;
        cov[rt]=-1;
        int mid=l+r>>1;
        if(l==r)return ;
        build(lson);
        build(rson);
    }
    void update(int l,int r,int rt,int L,int R,int c)
    {
        if(L<=l&&r<=R)
        {
            cov[rt]=c;
            sum[rt]=(r-l+1)*c;
            return ;
        }
        push_down(l,r,rt);
        int mid=l+r>>1;
        if(L<=mid) update(lson,L,R,c);
        if(R>mid)update(rson,L,R,c);
        push_up(rt);
    }
    int query(int l,int r,int rt,int L,int R)
    {
        if(L<=l&&r<=R)
            return sum[rt];
        push_down(l,r,rt);
        int mid=l+r>>1;
        int ret=0;
        if(L<=mid) ret+=query(lson,L,R);
        if(R>mid)ret+=query(rson,L,R);
        return ret;
    }
}dat[26];
int cnt[26];
int main()
{
    int n,m;read(n,m);
    rep(i,0,25)dat[i].build(1,n,1);  //建树
    for1(i,n){
        char ch;
        scanf("%c",&ch);
        dat[ch-'a'].update(1,n,1,i,i,1);  //初始化数,ch出现在第i个位置
    }
    while(m--)
    {
        int a,b,c;read(a,b,c);
        mm(cnt,0);
        rep(i,0,25)
        {
            cnt[i]+=dat[i].query(1,n,1,a,b);  //查询
            dat[i].update(1,n,1,a,b,0);  //置零
        }
        if(c==0)
        {
            int now=a;
            repp(i,25,0)if(cnt[i])
            {
                dat[i].update(1,n,1,now,now+cnt[i]-1,1);  //恢复
                now+=cnt[i];
            }
        }
        else
        {

            int now=a;
            rep(i,0,25)if(cnt[i])
            { 
                dat[i].update(1,n,1,now,now+cnt[i]-1,1);
                now+=cnt[i];
            }
        }
    }
    for1(i,n)rep(j,0,25)
        if(dat[j].query(1,n,1,i,i))
        {
            printf("%c",char(j+'a'));
            break;
        }
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值