牛客练习赛58(C D(BFS)E(因数分解)F(树剖+线段树))

题目链接

C-矩阵消除游戏

牛客练习赛58(C D(BFS)E(因数分解)F(树剖+线段树))_第1张图片

做法:水题,如果k>=min(n,m) 就是矩阵所有的和

k<=min(n,m)时就是dfs 二进制选取行 然后列 通过排序获得剩余的前k大个。

贪心有wa点,有个不错的数据在我代码最下方

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=17;
int r[N],c[N],n,m,k,a[N][N],ans,mi,sum,t[N];

int l[N],l1;

bool cmp(int x,int y)
{
    return x>y;
}
void dfs(int x,int k)
{
    //if(k>m) return ;
    if(k==0&&x<=n+1){
        ans=max(ans,sum);
        return ;
    }

    if(x>n){
        //if(k>m) return ;
        if(k==0){
            ans=max(ans,sum);
            return ;
        }
        k=min(k,m);
        for(int i=1;i<=m;++i) t[i]=c[i];

        for(int j=1;j<=l1;++j)
        for(int i=1;i<=m;++i) {
           t[i]-=a[l[j]][i];
        }

        sort(t+1,t+1+m,cmp);
        int res=sum;

        for(int i=1;i<=k;++i){
            res+=t[i];
        }
        if(res==412){
            printf("l1:%d\n",l1);

        }
        ans=max(ans,res);
        return ;
    }



    sum+=r[x];
    l[++l1]=x;
    dfs(x+1,k-1);
    --l1;
    sum-=r[x];
    dfs(x+1,k);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    mi=min(n,m);
    rep(i,1,n){
        rep(j,1,m) {
            scanf("%d",&a[i][j]);
            sum+=a[i][j];
            r[i]+=a[i][j];
            c[j]+=a[i][j];
        }
    }
//    for(int i=1;i<=m;++i) printf("%d\n",c[i]);
//    puts("");
//    puts("");
//    puts("");
//    puts("");
    if(k>=mi){
        printf("%d\n",sum);
        return 0;
    }
    sum=0;
    dfs(1,k);
    printf("%d",ans);
    return 0;
}

/*
5 6 2
0 0 0 2 2 0
2 1 1 1 1 1
2 1 1 2 2 1
0 0 0 2 2 0
0 0 0 1 1 0
ans=16
*/

D-迷宫

牛客练习赛58(C D(BFS)E(因数分解)F(树剖+线段树))_第2张图片

做法:简单观察可知,只能往右和往下走,那就随便bfs一下即可。

wa了的看我代码下的一个数据,这个数据能过,基本就能A了。

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10;
char s[N][N];
int n,m,a[N][N],vis[N][N];
int vs[N][N];
struct node
{
    int x,y,step;
    bool operator <(const node &o) const{
        return o.stepque;
    que.push({1,1,0});
    vis[1][1]=1;
    while(que.size())
    {
        node now=que.top();que.pop();
        //printf("x:%d y:%d t:%d\n",now.x,now.y,now.step);
        if(now.x==n&&now.y==m){
            printf("%d\n",now.step);
            return ;
        }
        int f=0;
        for(int i=0;i<2;++i){
            int x=now.x+dir[i][0];
            int y=now.y+dir[i][1];
            if(x<1||y<1||x>n||y>m) continue;
            if(a[x][y]) continue;

            vis[x][y]=1;
            if(now.step+f

E-最大GCD

牛客练习赛58(C D(BFS)E(因数分解)F(树剖+线段树))_第3张图片

献上题解:

牛客练习赛58(C D(BFS)E(因数分解)F(树剖+线段树))_第4张图片

做法:将ai 全部的质因子分解出来,然后按照质因子分块一下,对查询的p也质因子分解一下,离线搞一搞。

枚举p的因子块,同时也在枚举ai的因子块,判断一下ai的因子所在位置i是否在pi因子的范围即可,维护下最大值。

比较的简单 就暂时没有自己打代码了,献上出题人的代码

 

#include
using namespace std;
const int N=1e5+5;
struct node
{
    int l,r,id;
    node(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
    bool operator<(const node&o)const
    {
        if(o.r==r) return lv[N];
vectorp[N];
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        for(int j=1;j*j<=x;j++)
            if(x%j==0)
            {
                v[j].push_back(i);
                if(x/j!=j) v[x/j].push_back(i);
            }
    }
    for(int i=1;i<=q;i++)
    {
        int l,r,x;scanf("%d%d%d",&l,&r,&x);
        for(int j=1;j*j<=x;j++)
            if(x%j==0)
            {
                p[j].push_back(node(l,r,i));
                if(x/j!=j)
                    p[x/j].push_back(node(l,r,i));
            }
    }
    for(int i=1;i<=100000;i++)
    {
        if(!v[i].size()) continue;
        int k=0;
        sort(p[i].begin(),p[i].end());
        while(k

F-XOR TREE

牛客练习赛58(C D(BFS)E(因数分解)F(树剖+线段树))_第5张图片

树链剖分学习

题解分析些许复杂,虽然也对,个人感觉复杂了点。

分组个数 应该是i*(k-i+1)-1 因为f(2,2)不算一个路径(题目说的)

应该是

当k为偶数,所有位置的方法数都是奇数,那么树剖上查询就可以了。

当k为奇数,那么就是i为偶数的位置提供答案,按照树上,那么就隔一个顶点贡献一次。

 

那么树上我们就dfs给标号0  1   相邻的节点标号不同即可

那么当v1 端点是1  那我们只需要在标号为0 的线段树上区间查询即可。

树剖+两颗线段树即可。

#include
using namespace std;
typedef long long ll;
const int N=2e5+10;
vectorG[N];
int a[N];
int sum[2][4*N];
int n,q;
int sz[N],son[N],f[N],d[N],top[N],id[N],cnt;
void dfs1(int u,int fat,int dep)
{
    f[u]=fat;
    d[u]=dep;
    sz[u]=1;
    for(int v:G[u])
    {
        if(v==fat) continue;
        dfs1(v,u,dep+1);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int t)
{
    top[u]=t;
    id[u]=++cnt;
    if(!son[u]) return ;
    dfs2(son[u],t);
    for(int v:G[u])
    {
        if(v==son[u]||v==f[u]) continue;
        dfs2(v,v);
    }
}
void up(int id,int l,int r,int pos,int x,int ty)
{
    if(l>r) return ;
    if(l==r){
        sum[ty][id]=x;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,x,ty);
    else up(id<<1|1,mid+1,r,pos,x,ty);
    sum[ty][id]=(sum[ty][id<<1]^sum[ty][id<<1|1]);
}
int qu(int id,int l,int r,int ql,int qr,int ty){
    if(ql<=l&&r<=qr){
        return sum[ty][id];
    }
    int mid=l+r>>1;
    int res=0;
    if(ql<=mid) res^=qu(id<<1,l,mid,ql,qr,ty);
    if(qr>mid) res^=qu(id<<1|1,mid+1,r,ql,qr,ty);
    return res;
}
int getsum(int x,int y,int ty)
{
    int ans=0,fx=top[x],fy=top[y];
    while(fx!=fy){
        if(d[fx]>d[fy]){
            ans^=qu(1,1,n,id[fx],id[x],ty);
            x=f[fx],fx=top[x];
        }
        else{
            ans^=qu(1,1,n,id[fy],id[y],ty);
            y=f[fy],fy=top[y];
        }
    }
    if(id[x]>id[y]) ans^=qu(1,1,n,id[y],id[x],ty);
    else  ans^=qu(1,1,n,id[x],id[y],ty);
    return ans;
}
int main()
{
    scanf("%d%d",&n,&q);
	for(int i=1;i<=n;++i) {
        scanf("%d",&a[i]);
	}
	for(int i=1;i<=n-1;++i)
	{
	    int u,v;
        scanf("%d%d",&u,&v);
	    G[u].push_back(v);
	    G[v].push_back(u);
	}
	dfs1(1,0,1);
	dfs2(1,1);

	for(int i=1;i<=n;++i){
        up(1,1,n,id[i],a[i],d[i]%2);
	}

	while(q--)
    {
        int ty,u,v;
        scanf("%d%d%d",&ty,&u,&v);
        if(ty==1){
            up(1,1,n,id[u],v,d[u]%2);
        }
        else{
            if(d[u]%2!=d[v]%2){
                int ans1=getsum(u,v,d[u]%2);
                int ans2=getsum(u,v,(d[u]%2)^1);
                printf("%d\n",ans1^ans2);
            }
            else{
                printf("%d\n",getsum(u,v,(d[u]%2)^1));
            }
        }
    }
    return 0;
}

 

你可能感兴趣的:(牛客题解,数据结构--树链剖分)