首页 > 其他分享 >8.21

8.21

时间:2022-08-21 23:35:33浏览次数:67  
标签:return int long -- 异或 8.21 define

ABC249G

题意:

给定\(n\)张牌,每张牌正面是\(a_i\),背面是\(b_i\),要求从里面任选最少一张牌,使得证明的数字异或和不超过\(m\)的同时,背面数字异或和最大。

\(n\leq 2000,m,a_i,b_i\leq 2^{30}\)

题解:

对于两张牌\((a,b)\)和\((c,d)\)

和另外两张牌\((a,b)\)和\((a\oplus c,b\oplus d)\)是完全等价的。

可以互相异或一下发现所有情况都相同。

那么根据线性基理论,可以发现在互相异或之后,最多只有\(30\)张牌正面仍然不为零,且不能被其他牌表示出来,其他牌都可以通过异或让正面为零。

对于一张牌\((0,x)\)来说,这个\(x\)可以无条件使用。

那么这些\(x\)可以放入另一个线性基\(B\)中等着用来拼凑出最大值。

对于不能被其他数字表示出来的\(a\),可以放进线性基\(A\)中,用来拼凑限制\(m\),同时每一位有一个对应的异或值\(b\),表示选用了这个\(a\)就必须异或上一个\(b\)(背面的数字)。

然后对于限制\(m\),可以先强制要求\(A\)中异或和\(m\)的\(k\)位之前的部分相同,而第\(k\)位刚好\(m\)是\(1\),我们的异或值是\(0\),这样低位上就可以随意选择了。

这时候再把低位上的\(b\)和\(B\)中的值放入\(C\)中,来获得一个最大值。

但是按上面的方法,只能得到所有小于\(m\)的答案。

一个\(trick\)是提前把\(m+1\),这样就完美了。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=1e9+7,inv2=5e8+4,inf=2e15;
    void __init(int n=2000) {}
    struct line
    {
        int p[30];
        void clear()
        {
            for(int k=0;k<=29;++k) p[k]=0;
        }
        bool insert(int x)
        {
            for(int k=29;k>=0;--k) if((x>>k)&1)
            {
                if(!p[k])
                {
                    p[k]=x;return 1;
                }
                x^=p[k];
            }
            return 0;
        }
        int query(int x)
        {
            for(int k=29;k>=0;--k) x=max(x,x^p[k]);
            return x;
        }
    }A,B;
    inline void main()
    {
        int n,m;
        cin>>n>>m;
        ++m;
        vector<int> a(30,0),b(30,0);
        auto insert=[&](int &x,int &y) -> bool
        {
            for(int k=29;k>=0;--k) if((x>>k)&1)
            {
                if(a[k]) x^=a[k],y^=b[k];
                else
                {
                    a[k]=x;b[k]=y;
                    return 1;
                }
            }
            return 0;
        };
        bool flag=0;
        B.clear();
        for(int i=1;i<=n;++i)
        {
            int x,y;
            cin>>x>>y;
            if(!insert(x,y)) {B.insert(y),flag=1;}
        }
        for(int k=0;k<30;++k)
        {
            if(!a[k]) continue;
            if(a[k]>=m&&!flag)
            {
                cout<<"-1\n";
                return;
            }
            break;
        }
        int ans=0;
        for(int k=30;k>=0;--k) if((m>>k)&1)
        {
            int t1=0,t2=0;
            for(int i=29;i>k;--i) 
            {
                int b1=(m>>i)&1,b2=(t1>>i)&1;
                if(b1^b2) t1^=a[i],t2^=b[i];
            }
            if((t1>>k)&1) t1^=a[k],t2^=b[k];
            //cout<<k<<' '<<t1<<' '<<t2<<"!!"<<endl;
            if((t1>>k)&1||t1>=m) continue;
            line C=B;
            for(int i=0;i<k;++i) C.insert(b[i]);
            ans=max(ans,C.query(t2));
        }
        cout<<ans<<'\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

ABC238E

题意:

有一个长度为\(n\)的序列\(a\),有\(m\)个已知信息,每个形如\(a[l]\sim a[r]\)的和是已知的,最后能不能推出\(a[1]\sim a[n]\)的和?

\(n,m\leq 2*10^5\)

题解:

区间和可以转化成前缀和作差,那么\(a[l]\sim~a[r]\)的和的信息等价于知道了\(b[r]-b[l-1]\)的值,其中\(b\)是前缀和数组。

一开始的条件只有\(b[0]=0\),最后要知道\(b[n]\)的值。

那么每个信息,我们可以得知\(l-1\)和\(r\)是可以互相推导的,所以最后只要\(0\)和\(n\)联通,就可以得到\(a[1]\sim a[n]\)的和。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=1e9+7,inv2=5e8+4,inf=2e15;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m;
        cin>>n>>m;
        vector<int> f(n+1);
        for(int i=1;i<=n;++i) f[i]=i;
        function<int(int)> find=[&](int k) -> int
        {
            return f[k]==k?k:f[k]=find(f[k]);
        };
        for(int i=1;i<=m;++i)
        {
            int l,r;cin>>l>>r;
            f[find(l-1)]=find(r);
        }
        if(find(0)==find(n)) cout<<"Yes\n";
        else cout<<"No\n";
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

ABC128E

题意:

给定有\(n\)个位置\(x_i\)在\([st_i-0.5,ed_i-0.5]\)时间内施工,有\(m\)个人,第\(i\)个人从位置\(0\),时刻\(d_i\)开始往右走,一秒走一米,遇到第一个障碍停下,问每个人会走多少米?不会停下输出\(-1\)

\(n,m\leq 2*10^5\),其他数字小于等于\(10^9\)

题解:

离散化后线段树很显然,但是这样写不优雅。

先把施工时间转化到起点对应的出发时间去,然后按位置\(x_i\)从小到大排序,把每个人的出发时间塞到一个\(set\)里。

对于一个施工时间,二分找到对应的在这段时间内出发的人,把它们的答案改掉之后从\(set\)里删掉。

这样每个人只被删除一次。既不用离散化也不用数据结构

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=1e9+7,inv2=5e8+4,inf=2e15;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m;
        cin>>n>>m;
        struct node
        {
            int l,r,x;
            bool operator < (const node &t) const
            {
                return x<t.x;
            }
        };
        vector<node> a(n);
        for(int i=0;i<n;++i)
        {
            int l,r,x;
            cin>>l>>r>>x;
            l-=x; r=r-x-1;
            a[i]=(node){l,r,x};
        }
        sort(a.begin(),a.end());
        typedef pair<int,int> pr;
        set<pr> q;
        vector<int> ans(m,-1);
        for(int i=0;i<m;++i)
        {
            int x;cin>>x;
            q.insert(pr(x,i));
        }
        for(int i=0;i<n;++i)
        {
            auto l=q.lower_bound(pr(a[i].l,-inf));
            auto r=q.upper_bound(pr(a[i].r,inf));
            if(r==q.begin()||l==q.end()) continue;
            while(l!=r)
            {
                auto tmp=*l;
                auto pre=l++;
                q.erase(pre);
                ans[tmp.second]=a[i].x;
            }
        }
        for(int i=0;i<m;++i) cout<<ans[i]<<'\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

标签:return,int,long,--,异或,8.21,define
From: https://www.cnblogs.com/knife-rose/p/16611387.html

相关文章

  • 2022.8.21 多校周报
    总结牛客第九场A一眼看出是尺取法,就A了。B一道很简单的概率dp,状态和转移方程都写出来了,但想着搞前缀和优化,没想到差分,就卡死了,有点可惜。G马拉车加哈希,但卡了除了双......
  • 2022.8.21 线程池
    11、线程池(重点)线程池Executors:3大方法、7大参数、4种拒绝策略池化技术程序的运行,本质:占用系统的资源!优化资源的使用!==>引进了一种技术池化池线程池、连接池、内......
  • 2022.8.21 四大函数式接口与Stream流式计算
    12、四大函数式接口(重点)   函数接口:只有一个方法的接口    @FunctionalInterface publicinterfaceRunnable{     publicabstractvoidrun(......
  • 2022.8.21 Forkjoin与异步回调
    14、Forkjoin(分支合并)什么是ForkJoinForkJoin在JDK1.7, 并行执行任务!提高效率。在大数据量中!大数据:MapReduce(把大任务拆分为小任务)Forkjoin特点:工作窃取,这里......
  • 2022.8.21 读写锁与阻塞队列
    9、读写锁   自定义的缓存,没有加锁,就会出现一个没有写入完成,另一个突然插进来的情况 packagecom.xing.rw; ​ importjava.util.HashMap; importjava.util.......
  • 2022.8.21 JUC
    1、什么是JUC1、什么是juc(学习方法:官方文档+源码)   JUC——(java.util.concurrent)是一个包名的缩写,java工具类下的一个并发功能的包。该包下存放的均为多线程相......
  • 2022.8.21
    1.学习了MCS最大势算法,补充了弦图几个性质和konig定理的证明,做完了PPT。2.继续做了2道网络流24题,几道弦图相关的题目,看了昨天的CF,D题不是很懂3.最大流最小割定理,弦图是......
  • 8.21 随笔
     ******************************************************************************************.c  所写c源文件进行预处理.i  c文件替换宏,头文件包含(头文......
  • 8.5-8.21小记
    逸一时误一世了属于是。咕咕咕很久的总结。因为下午就开学了,只能这样写。好题算法大致感悟CF1098E万能欧几里得初见这算法,以后有时间补个学习笔记CF1178G......
  • 8.15~8.21
    家教第十五天最后一条,简单一点,给她们一点自信......