ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

8.1

2022-08-02 01:01:42  阅读:175  来源: 互联网

标签:8.1 int double long leq 端点 define


ABC262E

题意:

给定\(n\)个点\(m\)条边,选\(k\)个点染红,其他点染蓝,问有多少种方法,让偶数条边两端颜色不同?对\(998244353\)取模

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

题解:

假设有\(a\)染红色点的度数和,\(b\)条边两端都是红色的,\(c\)为两端颜色不同的边数

\[a=2*b+c \]

如果\(c\)是偶数,那么\(a\)一定要是偶数,直接枚举用了几个奇数度的点染红,

#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=5e5+10,mod=998244353,inv2=5e8+4,inf=2e9;
    const double pi=acos(-1.0);
    int n,m,k;
    int rd[N];
    int s[2];
    int fac[N],inv[N];
    inline int fast(int x,int k)
    {
        int ret=1;
        while(k)
        {
            if(k&1) ret=ret*x%mod;
            x=x*x%mod;
            k>>=1;
        }
        return ret;
    }
    inline void init(int n=5e5)
    {
        fac[0]=inv[0]=1;
        for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%mod;
        inv[n]=fast(fac[n],mod-2);
        for(int i=n-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod;
    }
    inline int C(int n,int m)
    {
        if(n<m||m<0) return 0;
        return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        cin>>n>>m>>k;
        for(int i=1;i<=m;++i)
        {
            int x,y;cin>>x>>y;
            ++rd[x],++rd[y];
        }
        init();
        for(int i=1;i<=n;++i)
        {
            ++s[rd[i]&1];
        }
        int ans=0;
        for(int i=0;i<n;i+=2)
        {
            ans+=C(s[1],i)*C(s[0],k-i)%mod;
            ans%=mod;
        }
        cout<<ans<<'\n';
    }
}
signed main()
{
    red::main();
    return 0;
}
/*

*/

CF1110E

题意:

给定数组\(c,t\),每次操作可以让\(c_i=c_{i+1}+c_{i-1}-c_i\)

问能不能通过操作让\(c\)和\(t\)相等。

数组长度\(\leq 10^5\),\(0\leq c_i,t_i\leq 2*10^9\)

题解:

首先,如果\(c_1\neq t_1\)或者\(c_n\neq t_n\),肯定不可能。

设\(a_i=c_{i}-c_{i-1}\)

那么操作过后

\[a_{i+1}=c_{i+1}-(c_{i+1}+c_{i-1}-c_i)=c_{i}-c_{i-1}=a_i\\ a_{i}=(c_{i+1}+c_{i-1}-c_i)-c_{i-1}=c_{i+1}-c_i=a_{i+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=2e5+10,mod=1e9+7,inv2=5e8+4,inf=2e9;
    const double pi=acos(-1.0);
    int n;
    int a[N],b[N];
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        cin>>n;
        bool flag=1;
        for(int i=1;i<=n;++i)
        {
            cin>>a[i];
        }
        for(int i=1;i<=n;++i)
        {
            cin>>b[i];
        }
        if(a[1]!=b[1]||a[n]!=b[n]) flag=0;
        for(int i=n;i>=1;--i)
        {
            a[i]-=a[i-1];
            b[i]-=b[i-1];
        }
        sort(a+1,a+n+1);
        sort(b+1,b+n+1);
        
        for(int i=1;i<=n;++i) flag&=(a[i]==b[i]);
        if(flag) cout<<"Yes\n";
        else cout<<"No\n";
        //c[i]=c[i+1]+c[i-1]-c[i];
        //c[i]-c[i-1]=c[i+1]-c[i];
        //d[i]=d[i+1]
    }
}
signed main()
{
    red::main();
    return 0;
}
/*
7 2 4 12
7 -5 2 8
7 -5 8 2
*/

P3760

题意:

给定一个序列,求所有子区间和的异或值。

\(n\leq 10^5,\sum a_i\leq 10^6\)

题解:

\(solution1\)

题目要求

\(\bigoplus \sum_{l=0}^n\sum_{r=l+1}^n(s[r]-s[l])\)

二进制数考虑按位

枚举位数\(k\)和右端点,如何快速求有多少满足要求的左端点?

如果右端点是\(1\),那么左端点:

要么是\(0\),且左端点低于第\(k\)位的部分小于等于右端点低于第\(k\)位的部分

要么是\(1\),且左端点低于第\(k\)位的部分大于右端点低于第\(k\)位的部分。

因为后者涉及做减法的时候会不会借位,如果借位,那么第\(k\)位的\(01\)就反转了。

右端点是\(1\)类似。

开两个树状数组,分别维护第\(k\)位是\(0\)和\(1\)的情况。

\(solution2\)

题解区的神仙还能继续优化。

下面引用自 Ntokisq 神仙

如果左右端点的第\(k\)位相同,那么其实就是在求逆序对数。

第\(k\)位不同时,其实是在算顺序对,但是贡献只有不同时才有,不妨用容斥,先不考虑相同不相同,再减去第\(k\)位相同的贡献。

第\(k\)位相同的贡献其实在算逆序对数的时候也算出来了。

那么怎么求序列的逆序对数呢?这个问题肯定是\(O(nlogn)\)的。

但是本题只要求逆序对的奇偶性。

有一个结论:如果一个排列经过\(x\)次交换邻项后变得有序,那么\(x\)和排列的逆序对数奇偶性相同。

可以推导出另一个结论:一个排列的逆序对数的奇偶性与\(n\)减去该排序的环数相同。

最终状态\(p_i=i\),那么有序的排序是有\(n\)个环的。

每次交换,要么减少一个环,要么增加一个环,减少一个环的话,还需要再花操作一次操作加回来,所以奇偶性也是相同。

求排列的环数可以\(O(n)\)

\(solution3\)

下面是另一种解法

可以直接算出每个数字出现多少次,因为算贡献是\(x-y=v\)的形式,且值域不是很大

设\(f_x\)是\(x\)作为区间和的出现次数,\(s_i\)是\(i\)作为前缀和的出现次数

\[f_x=\sum_{i=0}^ns_i*s_{i+x} \]

设\(s'\)是\(s\)翻转后的数组

\[f_x=\sum_{i=0}^ns_i*s'_{m-i-x} \]

就可以卷积了

\(solution4\)

固定左端点,枚举右端点,就可以求出左端点固定时的\([l,r]\)和的异或值。

那么每次左端点左移一位,其实就是把之前有的所有异或值全部\(+a[l]\),再把\(a[l]\)插入进去

考虑到\(\sum a_i\)很小,可以每次一位一位的加,然后用\(01trie\)实现。

\(01tire\)实现每次给所有数字\(+1\)是可以实现的:考虑倒着建\(trie\)树,第\(k\)层的儿子代表数字\(x\)的第\(k\)位是\(0\)还是\(1\),那么给所有数字\(+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=2e9;
    const double pi=acos(-1.0);
    int n;
    int a[N],s[N];
    struct BIT
    {
        int tr[N];
        inline void clear()
        {
            for(int i=1;i<=1000001;++i) tr[i]=0;
        }
        inline void update(int x,int k=1)
        {
            for(int i=x;i<=1000001;i+=lowbit(i)) tr[i]+=k;
        }
        inline int query(int y)
        {
            int sum=0;
            for(int i=y;i;i-=lowbit(i)) sum+=tr[i];
            return sum;
        }
    }T[2];
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        cin>>n;
        for(int i=1;i<=n;++i)
        {
            cin>>a[i];
            s[i]=s[i-1]+a[i];
        }
        int ans=0;
        for(int k=0;k<=20;++k)
        {
            T[0].clear();T[1].clear();
            int sum=0,tmp=(1<<k)-1;
            T[0].update(1);
            for(int i=1;i<=n;++i)
            {
                int now=0,val=s[i]&tmp;
                if((s[i]>>k)&1)
                {
                    now=T[0].query(val+1)+T[1].query(1000001)-T[1].query(val+1);
                    T[1].update(val+1);
                }
                else
                {
                    now=T[0].query(1000001)-T[0].query(val+1)+T[1].query(val+1);
                    T[0].update(val+1);
                }
                now%=2;
                sum^=now;
            }
            if(sum) ans|=(1<<k);
        }
        cout<<ans<<'\n';
    }
}
signed main()
{
    red::main();
    return 0;
}
/*
7 2 4 12
7 -5 2 8
7 -5 8 2
*/

标签:8.1,int,double,long,leq,端点,define
来源: https://www.cnblogs.com/knife-rose/p/16542363.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有