zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试110]题解

    也许是最后一篇了。

    A.最大或

    不错的签到题。

    对于二进制位来说,高位的一个1比低位的所有1的贡献总和还要大。

    显然,$r$必选,因为$r$中所有1的相对考前。那么考虑如何构造另一个数。

    首先$l$和$r$前几位相同的部分肯定是不能动的,所以从$l,r$不同那位开始贪心即可。如果$r$这位为0,只要构造的这个数爆不了$r$就让它的这位为1。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    int T;
    ll l,r;
    void work()
    {
    	scanf("%lld%lld",&l,&r);
    	ll res=0;bool ok=0;
    	for(int i=62;i>=0;i--)
    	{
    		int now=(r>>i)&1LL,nowl=(l>>i)&1LL;
    		if(now!=nowl)ok=1;
    		//cout<<i<<' '<<now<<' '<<nowl<<' '<<ok<<endl;
    		if(!now)
    			if((res|(1LL<<i))<=r&&ok)res|=1LL<<i;
    	}
    	printf("%lld
    ",r|res);
    }
    int main()
    {
    	freopen("maxor.in","r",stdin);
    	freopen("maxor.out","w",stdout);
    	scanf("%d",&T);
    	while(T--)work();
    	return 0;
    }
    

    B.答题

    题意可以转化为:求用所给的$n$个数组成的$2^n$个数中的第$k$大值,$k=ceil(2^n imes p)$。

    然后就是裸的折半搜索了。分别搜出前一半和后一半的子集和,然后二分答案。

    之后考虑如何求 从两组数里各取一个数,且令取出的两数和$ge$二分值的数对的个数。

    先把两组数排序,然后枚举第一组选到哪个,第二组维护一个倒着扫的单调指针即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,a[45],n1,n2,sz1,sz2;
    double p;
    ll kth;
    vector<int>s1,s2;
    void dfs(int x,int tot,int op)
    {
        if(!op&&x>n1)
        {
    
    
            s1.push_back(tot);
            return ;
        }
        if(op&&x>n)
        {
            s2.push_back(tot);
            return ;
        }
        dfs(x+1,tot,op);
        dfs(x+1,tot+a[x],op);
    }
    bool check(int val)
    {
        ll res=0;int j=sz2;
        for(int i=0;i<sz1;i++)
        {
            res+=sz2-j;
            while(j>0&&s2[j-1]+s1[i]>=val)j--,res++;
        }
        return res>=kth;
    }
    #define F
    int main()
    {
    #ifdef F
        freopen("answer.in","r",stdin);
        freopen("answer.out","w",stdout);
    #endif
        scanf("%d%lf",&n,&p);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        kth=(1LL<<n)-ceil(1.0*(1LL<<n)*p)+1;
        n1=n/2;
        dfs(1,0,0);dfs(n1+1,0,1);
        sz1=s1.size();sz2=s2.size();
        sort(s1.begin(),s1.end());
        sort(s2.begin(),s2.end());
        int l=0,r=1e9,ans;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        cout<<ans<<endl;
        return 0;
    }
    

    C.联合权值·改

    其实正解挺神的……但是它w范围这么小 不用白不用啊。

    直接开桶维护每个联合权值的个数,然后利用bitset去除三元环的情况即可。

    我没脸

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<bitset>
    using namespace std;
    #define pa pair<int,int>
    #define re register
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    typedef long long ll;
    const int N=3e4+5;
    int n,m,t;
    int to[N<<1],head[N],nxt[N<<1],tot,ansm;
    pa p[N<<1];
    bitset<N> s[N];
    ll w[N],anss,bu[N>>1],cnt[N>>1];
    inline void add(re int x,re int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    inline void print()
    {
        if(t!=2)printf("%d
    ",ansm);
        else puts("0");
        if(t!=1)printf("%lld
    ",anss);
        else puts("0");
    }
    #define F
    int main()
    {
    #ifdef F
        freopen("link.in","r",stdin);
        freopen("link.out","w",stdout);
    #endif
        n=read();m=read();t=read();
        for(re int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            p[i]=make_pair(x,y);
            add(x,y);add(y,x);s[x][y]=1;s[y][x]=1;
        }
        for(re int i=1;i<=n;i++)
            w[i]=read();
        for(re int x=1;x<=n;x++)
        {
            memset(bu,0,sizeof(bu));
            for(re int i=head[x];i;i=nxt[i])
            {
                int y=to[i];
                for(int k=1;k<=100;k++)
                    cnt[w[y]*k]+=bu[k];
                bu[w[y]]++;
            }
        }
        for(int i=1;i<=m;i++)
        {
            int now=(s[p[i].first]&s[p[i].second]).count();//cout<<i<<' '<<now<<endl;
            cnt[w[p[i].first]*w[p[i].second]]-=now;
        }
        for(int i=1;i<=10000;i++)
            anss+=1LL*i*cnt[i],ansm=max(ansm,cnt[i]?i:0);
        anss*=2;
        print();
        return 0;
    }
    
  • 相关阅读:
    my first android test
    VVVVVVVVVV
    my first android test
    my first android test
    my first android test
    ini文件
    ZZZZ
    Standard Exception Classes in Python 1.5
    Python Module of the Week Python Module of the Week
    my first android test
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11838305.html
Copyright © 2011-2022 走看看