ICode9

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

191004Day2---金华

2019-10-04 23:03:07  阅读:254  来源: 互联网

标签:ch ve int 个数 st 191004Day2 data1 金华


T1 异或

给你\(n\)个形如\([l_i,r_i]\)区间,设\(S_i=\bigcup_{j=1}^{i}[l_j,r_j]\),对于所有\(i\in[1,n]\),求\(\sum_{x,y\in S_i,x\leq y}[x\) \(xor\) \(y\)在二进制下一的个数有奇数个\(]\)。
\(n\leq10^5,0\leq l\leq r\leq2^{31}-1\)

sol:

首先发现维护的内容是区间并,想到有一个绝配的数据结构叫线段树。因为\(l\)和\(r\)的范围可以到\(2^{31}-1\),所以考虑动态开点或离散化。然后因为两个数异或后\(1\)的个数的奇偶性,与原来两个数\(1\)的个数之和的奇偶性相同,令\(X\)为区间内有几个含奇数个\(1\)的数,\(Y\)为有几个含偶数个\(1\)的数,所以只要分别处理出\(X\)和\(Y\),\(X\times Y\)即是答案。
方法1:动态开点线段树。这时会有一个非常良好的性质,就是对于一个线段树上的区间\([l,r]\),\(X\)的个数与\(Y\)的个数相等,于是一个区间的贡献可以在\(O(1)\)的时间内计算。
方法2:离散化+线段树。离散后可以不用动态开点,节省了空间,但同时失去了上一种做法的性质。现在继续考虑如何计算\(X\)和\(Y\)。我们把\(X_{[l,r]}\)拆成\(X_{[0,r]}-X_{[0,l-1]}\),对于\(Y\)同理。对于区间\([0,a]\),若\(a\)是奇数,则\(X_{[0,a]}=\frac{a}{2}+1\),若\(a\)为偶数,则还要判断\(a\)是否对\(X\)造成贡献。
方法3:离散化+set。常数有点大。Orz xuyuan
方法1代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}
const int N=100005,maxn=(1<<31)-1;
int n,cnt=1;
struct node{int l,r,data1,data2;bool vis;} st[N<<5];
void inst(int x,int l,int r,int lb,int rb){
    if(lb==rb){
        int num=0;
        for(int i=lb;i>0;i>>=1)
            if(i&1) num++;
        if(num&1) st[x].data1=1;
        else st[x].data1=0;
        st[x].data2=1-st[x].data1;
        st[x].vis=1;return;
    }
    if(l<=lb&&r>=rb){
        st[x].data2=st[x].data1=(rb-lb+1)>>1;
        st[x].vis=1;return;
    }
    int mid=(1ll*lb+rb)>>1;
    if(st[x].l==0) st[x].l=++cnt;
    if(l<=mid&&!st[st[x].l].vis) inst(st[x].l,l,r,lb,mid);
    if(st[x].r==0) st[x].r=++cnt;
    if(r>mid&&!st[st[x].r].vis) inst(st[x].r,l,r,mid+1,rb);
    st[x].data1=st[st[x].l].data1+st[st[x].r].data1;
    st[x].data2=st[st[x].l].data2+st[st[x].r].data2;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        inst(1,x,y,0,maxn);
        printf("%lld\n",1ll*st[1].data1*st[1].data2);
    }
    return 0;
}

T2 图论

给一个\(n\)个点的无向连通图,求解任意一种添加边的方式,使图变成一个连通的欧拉回路。
\(2\leq n\leq2000\)

sol:

思路1:首先对于那些奇数度的点,要想办法把它们变成偶数度。考虑建一张反图,在图上增广,具体就是对于两个奇数度的点,在反图上找到任一条路径,反转边的存在情况(原来选的边不选,原来不选的边选)。结束后整个图的点都为偶数度了,但不保证连通。当连通块个数大于两个时,只要把它们串成一个环即可;当连通块个数等于两个时,可以考虑在某一块中删除一条已有,或增加一条没有,且可选可不选的边,再把那条边的两个端点连向另一块中的某个点。
思路2:对于一个奇数个点的图,完全图显然是一个解;对于一个偶数个点的图,考虑在完全图中删除\(n/2\)条边,做法与上一种类似。
思路1代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}
const int N=1005;
int n,deg[N],st[N],ve[N],rev[N][N],ch[N][N],cnt,num;
char p[N][N];
bool vis[N],im;
void dfs(int x,int y,int la){
    vis[x]=1;
    for(int i=1;i<=n;i++){
        if(!rev[x][i]||i==la) continue;
        if(i==y){ch[x][i]^=1;ch[i][x]^=1;im=1;return;}
        if(vis[i]) continue;
        ch[x][i]^=1;ch[i][x]^=1;
        dfs(i,y,x);
        if(im) return;
        ch[x][i]^=1;ch[i][x]^=1;
    }
}
void print(){
    puts("Yes");
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            if(p[i][j]=='1'||ch[i][j]||ch[j][i]) putchar('1');
            else putchar('0');
        puts("");
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",p[i]+1);
        for(int j=1;j<=n;j++){
            if(p[i][j]=='1') deg[j]++;
            if(p[i][j]=='1'||i==j) rev[i][j]=0;
            else rev[i][j]=1;
        }
    }
    for(int i=1;i<=n;i++){
        if(deg[i]&1) st[++cnt]=i;
    }
    if(cnt&1){puts("No");return 0;}
    for(int i=1;i<=cnt;i+=2){
        memset(vis,0,sizeof(vis));
        im=0;dfs(st[i],st[i+1],0);
        if(!im){puts("No");return 0;}
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(ch[i][j]) deg[j]++;
        }
    for(int i=1;i<=n;i++)
        if(deg[i]==0) ve[++num]=i;
    if(num==1){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                if(ch[i][j]){
                    ch[i][j]=ch[j][i]=0;
                    ch[ve[1]][i]=ch[i][ve[1]]=1;
                    ch[ve[1]][j]=ch[j][ve[1]]=1;
                    print();return 0;
                }
            }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                if(ch[i][j]==0&&i!=j&&p[i][j]=='0'){
                    ch[i][j]=ch[j][i]=1;
                    ch[ve[1]][i]=ch[i][ve[1]]=1;
                    ch[ve[1]][j]=ch[j][ve[1]]=1;
                    print();return 0;
                }
            }
        puts("No");return 0;
    }
    if(num==n){
        for(int i=1;i<n;i++)
            ch[i][i+1]=ch[i+1][i]=1;
        ch[n][1]=ch[1][n]=1;
        print();return 0;
    }
    int x,y;
    for(int i=1;i<=n;i++)
        if(deg[i]>0){
            x=i;
            for(int j=i+1;j<=n;j++)
                if(deg[j]>0){y=j;break;}
            break;
        }
    ch[x][ve[1]]=ch[ve[1]][x]=1;
    ch[y][ve[1]]=ch[ve[1]][y]=1;
    ch[x][ve[2]]=ch[ve[2]][x]=1;
    ch[y][ve[num]]=ch[ve[num]][y]=1;
    for(int i=2;i<num;i++){
        ch[ve[i]][ve[i+1]]=ch[ve[i+1]][ve[i]]=1;
    }
    print();return 0;
}

T3 乘积

以后补吧。

标签:ch,ve,int,个数,st,191004Day2,data1,金华
来源: https://www.cnblogs.com/zxynothing/p/11623598.html

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

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

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

ICode9版权所有