• [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;
    }
    
  • 相关阅读:
    如何用机器学习强化市场营销活动。
    大数据统计脚本, 分城市订单统计
    宇宙常量与增长黑客。
    病毒传播效果的衡量公式
    浅谈对增长黑客的理解
    大数据分析, 数据挖掘, 机器学习,找到产品改进的爆点。
    R语言的日期运算
    安装语言包-英文(美国)
    selenium page objects
    logging模块
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11838305.html
Copyright © 2020-2023  润新知