王者场ABC题解

反思一下:简单题没想好就急着敲,浪费时间,难的题反而做的快,因为想好了后代码是不会出问题的。

所以还是要先想清楚过程确定没问题在敲代码,主要是想的时间。

  • A:奇怪的排序问题

想清楚每次操作的过程就好做了:

肯定是从高往低去处理,(因为无论你怎么动矮的,都不会让高的人往后走)

对于当前最高的人x,如果他不是最后面的一个,则需要花费1次把他移动到最后排。(且他原本的位置置为空)

如果他是当前最后排,则不需要移动。

处理过程注意维护空的位置即可。

const int M = 1e6 + 10;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 
     * @param a int整型vector 
     * @return int整型
     */
    int wwork(int n, vector<int>& v) {
        // write code here
        int r=n-1;
        int mp[1000007]={0}; 
        for(int i=0;i<n;i++){
            mp[v[i]-1]=i;
        }
        int nm=0;
        for(int i=n-1;i>=0;i--){

            while(r>=0 && v[r]==-1)r--;
        //    cout<<i<<" "<<mp[i]<<"  "<<r<<" "<<nm<<endl;
            if(mp[i]!=r)nm++,v[mp[i]]=-1;
            else{
                r--;
            }

        }
        return nm;
    }
};
  • B:XOR和
    两种方法:

方法一:打表找规律(推荐这种,尤其是表很快就能打出来的题,能省去很多时间)
打表发现:

对于一个数x,其初始f[x]=0;

如果一个数x是1的倍数,则f[x]+=1,

如果一个数x是2的的倍数,则f[x]+=2;

如果一个数x是4的的倍数,则f[x]+=4;

如果一个数x是8的的倍数,则f[x]+=8;

…………

然后直接枚举2的次幂即可。

方法二:数学推导
设一个数n,其最低位的1在y上。

则n-1 ^ n = ((1<<y) -1 ); (因为高于y的位n和n-1都不变,低于y的位刚好是n为0,n-1为1)

比如一个数 (二进制表示)

10100

其减一为:

10011

则10100^10011 = 11 = 3

然后就转化为方法一中的规律去枚举求解即可

typedef long long ll;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 
     * @return long长整型
     */

long long Sum(int n) {
        // write code here
        ll sm=(1+n)*n/2;
        ll ans=0,nw=0;
        for(int i=0;i<31;i++){
            ll tp=1ll<<i;
            nw=tp;
            ans+=nw*(n/tp);
        }
        return ans;
    }
};
  • C:牛牛的路径和
    枚举每一位,分开进行算贡献。

只考虑第i位,树上点权就只有0/1两种,我们求的是每个全1连通块内,路径个数nm,然后让nm*(1<<x)就是这个连通块的点在第i位上对答案的贡献了。

枚举所有位即可算出最终答案。

const int M = 1e5+7;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 点的个数
     * @param u int整型vector 每条边的起点
     * @param v int整型vector 每条边的终点
     * @param p int整型vector 每个点的价值
     * @return long长整型
     */

    int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
int a[M],vs[M];
long long nm;
void dfs(int x){
    vs[x]=1;
    nm++;
    for(int i=head[x];i;i=ee[i].nxt){
        int y=ee[i].to;
        if(vs[y]||a[y]==0)continue;
        dfs(y);
    }
}
long long solve(int n, vector<int>& u, vector<int>& v, vector<int>& p) {
        // write code here
        init(n);
        for(int i=0;i<n-1;i++){
            a[i]=p[i];
            add(u[i],v[i],1);
            add(v[i],u[i],1);
        }
        long long ans=0;
        for(int sta=0;sta<=20;sta++){
            for(int i=0;i<n;i++)if((p[i]>>sta)&1)a[i]=1;else a[i]=0;
            memset(vs,0,sizeof(vs));
            for(int i=0;i<n;i++){
                if(vs[i]||a[i]==0)continue;
                nm=0;
                dfs(i);
                ans+=(nm+nm*(nm-1)/2)*(1<<sta);
            }
        }
        return ans;
    }
};