补题:The Preliminary Contest for ICPC China Nanchang National Invitational

比赛链接


 A. PERFECT NUMBER PROBLEM

一开始想打表,发现实在太慢了,最后百度的perfect number...

#include <cstdio>
using namespace std;

int main()
{
    printf("6\n28\n496\n8128\n33550336\n");
    return 0;
}
View Code

B. Greedy HOUHOU

待补


C. Angry FFF Party

待补


D. Match Stick Game

待补


E. Card Game

待补


F. Information Transmitting

待补


G. tsy's number

待补


H. Coloring Game

待补


I. Max answer

待补


J. Distance on the tree

在线处理有点麻烦,没办法避免主席树

所以我们考虑将查询的$k$排序后离线做,每询问一次,就把边权小于$k$的边计数设为$1$(由于$k$是递增的,所以每条边只会遍历到一次,复杂度$O(N)$),于是问题转化为求$u$到$v$的路径上计数的和

我的做法是先把整棵树树链剖分上去,然后对于每条链维护一个树状数组,记录的是从顶点到链上某一位置的计数之和

于是可以处理每次查询了:如果这条链完全包含在路径内,将整条链的区间和加到$ans$中;否则只加入区间的某一段之和(所以在树剖的时候,需要记录每个顶点在链上的位置)

动态开数组是C++课上学到的hhh

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N=100005;

struct tri
{
    int x,y,w,id;
    tri()
    {
    }
    tri(int a,int b,int c,int d=0)
    {
        x=a,y=b,w=c,id=d;
    }
};

inline bool operator < (tri a,tri b)
{
    return a.w<b.w;
}

struct Tree
{
    int *t,sz,sum;
    Tree()
    {
        t=NULL;
        sz=sum=0;
    }
    ~Tree()
    {
        delete []t;
    }
    
    void Init(int size)
    {
        sz=size;
        t=new int[sz+5];
        for(int i=1;i<=sz;i++)
            t[i]=0;
    }
    
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    
    inline void Add(int pos)
    {
        sum++;
        while(pos<=sz)
            t[pos]++,pos+=lowbit(pos);
    }
    inline int Query(int pos)
    {
        int res=0;
        while(pos)
            res+=t[pos],pos-=lowbit(pos);
        return res;
    }
}t[N];

int n,m;
tri e[N],q[N];
vector<int> v[N];

int fa[N],sz[N],dep[N],son[N];

inline void dfs1(int x,int f)
{
    fa[x]=f;
    sz[x]=1;
    dep[x]=dep[fa[x]]+1;
    
    for(int i=0;i<v[x].size();i++)
    {
        int next=v[x][i];
        if(next==fa[x])
            continue;
        
        dfs1(next,x);
        sz[x]+=sz[next];
        if(!son[x] || sz[next]>sz[son[x]])
            son[x]=next;
    }
}

int top[N],pos[N];

inline void dfs2(int x,int cur)
{
    top[x]=cur;
    pos[x]=(top[fa[x]]==cur?pos[fa[x]]:0)+1;
    
    if(son[x])
        dfs2(son[x],cur);
    if(!son[x])
        t[top[x]].Init(pos[x]);
    
    for(int i=0;i<v[x].size();i++)
    {
        int next=v[x][i];
        if(next==son[x] || next==fa[x])
            continue;
        
        dfs2(next,next);
    }
}

int ans[N];

int main()
{
//    freopen("input.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        e[i]=tri(x,y,w);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    sort(e+1,e+n);
    
    for(int i=1;i<=m;i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        q[i]=tri(x,y,w,i);
    }
    sort(q+1,q+m+1);
    
    dfs1(1,0);
    dfs2(1,1);
    
    int p=1;
    for(int i=1;i<=m;i++)
    {
        while(p<n && e[p].w<=q[i].w)
        {
            int des=(fa[e[p].x]==e[p].y?e[p].x:e[p].y);
            t[top[des]].Add(pos[des]);
            p++;
        }
        
        int res=0;
        int x=q[i].x,y=q[i].y;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
            {
                res+=t[top[x]].Query(pos[x]);
                x=fa[top[x]];
            }
            else
            {
                res+=t[top[y]].Query(pos[y]);
                y=fa[top[y]];
            }
        }
        if(dep[x]>dep[y])
            res+=t[top[x]].Query(pos[x])-t[top[x]].Query(pos[y]);
        else
            res+=t[top[x]].Query(pos[y])-t[top[x]].Query(pos[x]);
        ans[q[i].id]=res;
    }
    
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
View Code

K. MORE XOR

很明显是结论题

我们应当手算依次手算$f(l,r)$,$g(l,r)$,$w(l,r)$的表达式

由于所有运算都是异或,所以只要一个数出现偶数次,它对结果的贡献就是$0$

那么我们计算的$f$,$g$,$w$的表达式,应当表示为多个元素的异或

最后能发现规律:$w$的结果与分别以$l$、$l+1$为起点、每隔四个元素的异或值有关(注意边界)

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int N=100005;

int T,n,q;
int a[N];
int pre[N];

int main()
{
//    freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        
        memset(pre,0,sizeof(pre));
        for(int i=1;i<=n;i++)
        {
            if(i<4)
                pre[i]=a[i];
            else
                pre[i]=a[i]^pre[i-4];
        }
        
        scanf("%d",&q);
        while(q--)
        {
            int l,r,pnt,ans=0;
            scanf("%d%d",&l,&r);
            
            pnt=r;
            while(pnt%4!=l%4)
                pnt--;
            
            if(((r-l)/2+1)%2==1)
                ans^=(pre[pnt]^(l<4?0:pre[l-4]));
            
            if(l!=r)
            {
                pnt=r;
                while(pnt%4!=(l+1)%4)
                    pnt--;
            
                if(((r-l+1)/2)%2==1)
                    ans^=(pre[pnt]^(l+1<4?0:pre[l+1-4]));
            }
                printf("%d\n",ans);
        }
    }
    return 0;
}
View Code

L. qiqi'tree

待补


M. Subsequence

待补

猜你喜欢

转载自www.cnblogs.com/LiuRunky/p/The_Preliminary_Contest_for_ICPC_China_Nanchang_National_Invitational.html
今日推荐