「CSP-S模拟赛」2019第一场

目录

  • T1 小奇取石子

    • 题目
    • 考场思路
    • 正解
  • T2 「CCO 2017」专业网络
    • 题目
    • 考场思路
    • 题解
  • T3 「ZJOI2017」线段树
    • 题目
    • 考场思路
    • 正解


这场考试感觉很奇怪。
\(T1、T2\) 都缺一个小特判。
\(T3\) 打了个比暴力优的暴力 还是暴力,但是不知道为什么 \(WA\) 穿了。
考试的时候还玩扫雷...
其实,菜是原罪啊...
___

T1 小奇取石子

题目

点这里

考场思路

刚开始差点被自己坑了,开考 \(5min\) 就码出了一个可以惨痛爆零的 \(01\) 背包。
结果还好的是交卷前几分钟自己出了个小数据卡掉自己,然后就码出一个 \(80pts\) 的代码。
首先根据数据将方法分开。
对于 \(A、B\) 两组数据,很明显暴力都可以过,这个没有问题。
对于 \(C\) 组数据,定义 \(dp[i]\):得到石子数为 \(i\) 时的最小选择石子堆。
状转见代码。

#include<cstdio>
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define dep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
#define cg (c=getchar())
inline int qread(){
    int x=0,f=1;char c;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return x*f;
}
template<class T>inline void qread(T& x){
    x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
#undef cg
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}

const int MAXN=200;
const int MAXK=2500;
const int INF=0x3f3f3f3f;

int n,m,k,a[MAXN+5],maxx;
int dp[MAXK+5];

inline void init(){
    qread(n,m,k);
    for(int i=1;i<=n;++i)qread(a[i]);
}

void dfs(const int i,const int x,const int w){
    if(w>k||x>m)return;
    maxx=Max(maxx,w);
    if(i>n)return;
    dfs(i+1,x+1,w+a[i]);
    dfs(i+1,x,w);
}

inline void getDp(){
    rep(i,1,k)dp[i]=INF;
    rep(i,1,n)rep(j,a[i],k)dp[j]=Min(dp[j],dp[j-a[i]]+1);
    dep(i,k,1)if(dp[i]<=m){maxx=i;break;}
}

signed main(){
    // freopen("stone.in","r",stdin);
    // freopen("stone.out","w",stdout);
    init();
    if(n<=20)dfs(1,0,0);
    else getDp();
    printf("%d\n",maxx);
    return 0;
}

正解

其实就是我的考场代码改个细节,为了保存上一个 \(i\) 的状态,\(j\) 应该从大到小枚举
不知道我考场的时候脑子 what 了,这个细节都打错了...

#include<cstdio>
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define dep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
#define cg (c=getchar())
inline int qread(){
    int x=0,f=1;char c;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return x*f;
}
template<class T>inline void qread(T& x){
    x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
#undef cg
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}

const int MAXN=200;
const int MAXK=2500;
const int INF=0x3f3f3f3f;

int n,m,k,a[MAXN+5],maxx;
int dp[MAXK+5];

inline void init(){
    qread(n,m,k);
    for(int i=1;i<=n;++i)qread(a[i]);
}

void dfs(const int i,const int x,const int w){
    if(w>k||x>m)return;
    maxx=Max(maxx,w);
    if(i>n)return;
    dfs(i+1,x+1,w+a[i]);
    dfs(i+1,x,w);
}

inline void getDp(){
    rep(i,1,k)dp[i]=INF;
    rep(i,1,n)dep(j,k,a[i])dp[j]=Min(dp[j],dp[j-a[i]]+1);
    dep(i,k,1)if(dp[i]<=m){maxx=i;break;}
}

signed main(){
    // freopen("stone.in","r",stdin);
    // freopen("stone.out","w",stdout);
    init();
    if(n<=20)dfs(1,0,0);
    else getDp();
    printf("%d\n",maxx);
    return 0;
}

T2 「CCO 2017」专业网络

题目

点这里

考场思路

所谓信息竞赛,其实就是面向数据编程

看看数据范围,发现前两组很好骗分,然后就可以对于这两组数据进行骗分了...

#include<cstdio>
#include<algorithm>
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define dep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
using namespace std;
#define cg (c=getchar())
inline int qread(){
    int x=0,f=1;char c;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return x*f;
}
template<class T>inline void qread(T& x){
    x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
#undef cg
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}

const int MAXN=2e5;
const int INF=0x3f3f3f3f;

int N,maxb,ans=INF;
struct node{
    int a,b;
    inline void input(){qread(a,b);if(a==0)b=0;}
    node(){}
    node(const int A,const int B):a(A),b(B){}
    bool operator<(const node t){return b==t.b?a<t.a:b<t.b;}
}p[MAXN+5];

inline void init(){
    qread(N);
    rep(i,1,N)p[i].input(),maxb=Max(maxb,p[i].b);
}

inline void dfs30(const int,const int,const int);
inline bool cmp30(const node _x,const node _y){
    return _x.a==_y.a?_x.b<_y.b:_x.a<_y.a;
}
inline void pts30(){
    sort(p+1,p+N+1,cmp30);
    dfs30(0,0,0);
}

inline void dfs30(int tot,int state,const int cost){
    if(tot==N)return (void)(ans=Min(ans,cost));
    if(cost>ans)return;

    rep(i,1,N)if(!(state&(1<<(i-1)))&&tot>=p[i].a)++tot,state|=(1<<(i-1));

    if(tot==N)return (void)(ans=Min(ans,cost));

    rep(i,1,N)if(!(state&(1<<(i-1))))
        dfs30(tot+1,state|(1<<(i-1)),cost+p[i].b);
}

inline bool cmp15(const node _x,const node _y){
    return _x.a>_y.a;
}
inline void pts15(){
    sort(p+1,p+N+1,cmp15);
    int l=1,r=N,tot=0;ans=0;
    while(l<=r){
        while(p[r].a<=tot)--r,++tot;
        if(r<l)break;
        if(p[l].a>tot)++ans;
        ++l,++tot;
    }
}

signed main(){
    // freopen("network.in","r",stdin);
    // freopen("network.out","w",stdout);
    init();
    if(maxb==1)pts15();
    else pts30();
    printf("%d\n",ans);
    return 0;
}

题解

其实,这道题跟 《信息奥赛一本通》中的不守交规 有异曲同工之妙。——\(\text{JZM}\) 大佬

首先,我们跟每一个人建立友谊关系的状态肯定唯一。
假如我们跟 \(i\) 交朋友之前,我们已经交了 \(j\) 个朋友。
那么,肯定不存在 \(k(k\neq i)\) 使得我们在与 \(k\) 交朋友之前已经交了 \(j\) 个朋友。
所以,我们的 \(j\) 可以取 \([0,N-1]\) 之中的数。
那么,我们只需要在交这 \(N\) 个朋友的时候,将他们对应到这 \([0,N-1]\) 的 \(N\) 个数中去即可。
而如果 \(i\) 是不用花费的,那么它的对应值一定在 \([A_i,N-1]\) 中的一个数。
贪心地,我们首先要满足那些 \(B_i\) 较大的数,这样我们的花费就会尽可能的少。
而为了让区间能够对应的数尽可能多,我们的搜索需要从 \(A_i\) 开始枚举。
而对于一个 \(i\),如果在 \([A_i,N-1]\) 中已经没有数没有被对应到,那么它就一定需要支付费用。
那么这一段的代码也就很好写了

for(int i=1,loc;i<=N;++i){
    bool f=true;
    for(int j=p[i].a;j<N;++j)if(!vis[j]){
        vis[j]=true,f=false;
        break;
    }
    if(!f)ans+=p[i].b;
}

然而这是 \(O(N^2)\) 的算法,它最多只能得到 \(60pts\),因此我们需要用到并查集优化。
时间复杂度接近于 \(O(N)\),我省掉了反阿克曼函数,它增长地太慢了。

#include<cstdio>
#include<algorithm>
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define dep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
using namespace std;
#define cg (c=getchar())
inline int qread(){
    int x=0,f=1;char c;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return x*f;
}
template<class T>inline void qread(T& x){
    x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
#undef cg
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}

const int MAXN=2e5;

int N,ans,pre[MAXN+5];bool vis[MAXN+5];
struct node{
    int a,b;
    inline void input(){qread(a,b);}
    node(){}
    node(const int A,const int B):a(A),b(B){}
    bool operator<(const node t){return b==t.b?a<t.a:b>t.b;}
}p[MAXN+5];

inline void init(){
    qread(N);
    for(int i=1;i<=N;++i)p[i].input();
    sort(p+1,p+N+1);
}

inline int findSet(const int u){
    return u==pre[u]?u:pre[u]=findSet(pre[u]);
}

inline void calc(){
    for(int i=1;i<=N;++i)pre[i]=i;
    for(int i=1,loc;i<=N;++i){
        loc=findSet(p[i].a);
        if(loc>=N)ans+=p[i].b;
        else pre[loc]=loc+1;
    }
}

signed main(){
    init();
    calc();
    printf("%d\n",ans);
    return 0;
}

T3 「ZJOI2017」线段树

题目

点这里

考场思路

考试的时候,我想到一种时间复杂度只有 \(O(nm)\) 的暴力算法 虽然还是暴力,但是时间少了点
但是我没有仔细思考其正确性。
大致思路是这样的:
在询问区间 \([l,r]\) 的时候,假如有某一段区间 \([l',r']\) 与 \(u\) 不在大树的同一棵子树上,那么就计算区间 \([l',r']\) 的贡献。
但是这样做有问题,假若区间 \([l',r'']\) 被包含于 \([l,r]\) ,并且 \(r'\) 与 \(r''\) 不在同一棵子树内,那么我的算法就会使得答案 \(ans\) 变大。
因为这样做会使我寻找的可以被拼成区间 \([l,r]\) 的点变多,自然而然,\(ans\) 也就变大了。
附个代码

#include<cstdio>
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define dep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
#define cg (c=getchar())
inline int qread(){
    int x=0,f=1;char c;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return x*f;
}
template<class T>inline void qread(T& x){
    x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
#undef cg
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}

const int MAXN=2e5;

struct node{
    int l,r,mid,d,lc,rc;
    node(){lc=rc=0;}
    node(const int L,const int R,const int M,const int D):l(L),r(R),mid(M),d(D){lc=rc=0;}
}tre[(MAXN<<1)+5];

int N,q,ncnt,ans;
int s[(MAXN<<1)+5],tail;

inline int buildtre(const int pre,const int l,const int r,const int d){
    int now=++ncnt;
    if(l==r)return tre[now]=node(l,r,0,d),now;
    tre[now]=node(l,r,qread(),d);
    tre[now].lc=buildtre(now,l,tre[now].mid,d+1);
    tre[now].rc=buildtre(now,tre[now].mid+1,r,d+1);
    return now;
}

inline void init(){
    qread(N);
    buildtre(0,1,N,1);
}

void getNode(const int i,const int l,const int r){
    if(l<=tre[i].l&&tre[i].r<=r)return (void)(s[++tail]=i);
    if(l<=tre[i].mid)getNode(tre[i].lc,l,r);
    if(r>tre[i].mid)getNode(tre[i].rc,l,r);
}

inline void calc(const int lca,const int u){
    while(tail>0)ans+=tre[s[tail--]].d+tre[u].d-2*tre[lca].d;
}

void algor(const int i,const int u,const int l,const int r){

    // printf("algor : %d %d %d %d\n",i,u,l,r);

    if(u==i){
        getNode(i,l,r);
        calc(i,i);
        return;
    }

    if(tre[i].lc<=u&&u<tre[i].rc&&r<=tre[i].mid)algor(tre[i].lc,u,l,r);
    else if(u>=tre[i].rc&&l>tre[i].mid)algor(tre[i].rc,u,l,r);
    //以上皆为同方向的子树时
    else{
        //在不同向
        //此时一定可以保证, i 即为他们的 lca
        if(u>=tre[i].rc&&l<=tre[i].mid){//当询问区间的 部分/全部 在左边, 点在右边时
            getNode(tre[i].lc,l,Min(tre[i].mid,r));
            calc(i,u);
            if(r>tre[i].mid)algor(tre[i].rc,u,tre[i].mid+1,r);
        }
        else if(tre[i].lc<=u&&u<tre[i].rc&&r>tre[i].mid){//当询问区间的 部分/全部 在右边, 点在左边时
            getNode(tre[i].rc,Max(tre[i].mid+1,l),r);
            calc(i,u);
            if(l<=tre[i].mid)algor(tre[i].lc,u,l,tre[i].mid);
        }
        /*
        else if(u==i){//当点就是当前的点的时候, 直接在其子树中寻找区间的点进行计算
            getNode(i,l,r);
            calc(i,i);
        }
        */
    }
}

inline void getQuery(){
    int q=qread(),u,l,r;
    while(q--){ans=0;
        qread(u,l,r);
        algor(1,u,l,r);
        printf("%d\n",ans);
    }
}

signed main(){
    // freopen("0.in","r",stdin);
    // freopen("tree.out","w",stdout);
    init();
    // puts("finished input!");
    getQuery();
    return 0;
}

正解

一道编码较为困难的数据结构题。
首先,我们解决询问的区间的问题。
看下面这张图

其实这个就是题目描述里面的那张图。
假设我们需要访问区间 \([2,4]\),应该怎么做呢?
方法一
你可以肉眼看...虽然这样好像不能交到 \(OJ\) 上去...
但是我们可以看出我们要找的节点是 \((2-3)\) 与 \((4-4)\)。
方法二
使用类似于普通线段树的方法进行区间查找,这样的复杂度对于这样的广义线段树来说大概是 \(O(n)\) 的。
方法三
可以用类似于 \(\text{zkw}\) 线段树 的方式。
我们要访问区间 \([2,4]\) ,那么左边从 \((1-1)\) 开始,右边从 \((5-5)\) 开始,一起往上爬。
如果左边点往上爬,发现它是父亲节点的左儿子,那么其父节点的右儿子是一定是我们要找的点。
如果右边点往上爬,发现他是父节点的右儿子,那么其父节点的左儿子是一个是我们要找的点。
大概搜索的结果就是
其中,被红色笔圈起来的点是我们要特殊注意的,而蓝色下划线是我们要取到的点。
那么这样做的时间复杂度?不用说,\(O(n)\)。

先把这些方法放在一边,看一看我们需要求什么。
题目似乎给出\[ans=\sum_{v\in S[l,r]}dis(u,v)\]令 \(d[u]\):点 \(u\) 的深度。
我们可以将 \(dis(u,v)\) 换成用 \(lca\) (时间复杂度 \(O(logn)\) 左右,不要忽略了)来表示,那么就有\[ans=\sum_{v\in S[l,r]}d[u]+d[v]-2\cdot d[lca(u,v)]\]假设我们最后可以处理出,我们找到的满足 \(v\in S[l,r]\) 的点共有 \(t\) 个,那么这个公式可以再展开:\[ans=t\cdot d[u]+\sum_{v\in S[l,r]}d[v]-\sum_{v\in S[l,r]}2\cdot d[lca(u,v)]\]然而这个式子似乎再也不能往下化简了。

我们再往回看,我们已分析出的两种方法 人为忽略第一种
假若我们用 方法二 ,那么我们似乎并不能做什么优化,只有用标准的线段树做法,时间复杂度还是 \(O(n)\)。
假若我们用 方法三 ,那么我们似乎可以用树上差分
怎么个差分法呢?
记录一下每个点的信息

  • \(tls[u]\):从根到 \(u\) 一共有多少左儿子是没有经过的
  • \(trs[u]\):从根到 \(u\) 一共有多少右儿子是没有经过的
  • \(tdls[u]\):从根到 \(u\) 一共没见过的左儿子的深度之和
  • \(tdrs[u]\):从根到 \(u\) 一共没见过的右儿子的深度之和

那么我们怎么求以上内容呢?
可以在建树的时候顺便处理出来。
假设我们有一个点 \(fa\),其深度为 \(d\),它的左儿子是 \(lc\),右儿子是 \(rc\)。
那么,若 \(rc\) 存在,且 \(lc\) 存在,则满足
\[trs[lc]=trs[fa]+1,tdrs[lc]=tdrs[fa]+(d+1),tls[lc]=tls[fa],tdls[lc]=tdls[fa]\]而若 \(rc\) 不存在,则有
\[trs[lc]=trs[fa],tdrs[lc]=tdrs[fa],tls[lc]=tls[fa],tdls[lc]=tdls[fa]\]如果 \(lc\) 存在,且 \(rc\) 存在,则满足
\[trs[rc]=trs[fa],tdrs[rc]=tdrs[fa],tls[rc]=tls[fa]+1,tdls[rc]=tdls[fa]+(d+1)\]然后,我们就可以在建树,或者是输入建树时预处理出以上内容即可。
接着之前说的树上差分
假若我们要求区间 \([a,b]\) ,那么我们就从 \((a-1,a-1)\) 与 \((b+1,b+1)\) 开始往上爬。
找到它们的最近公共祖先 \(lca\),那么我们要求的公式中的 \(t、\sum_{v\in S[l,r]}d[v]\) 都可以用树上差分解决。
即 \(t\) 满足
\[t=trs[leafu[a-1]]-trs[lca]+tls[leafu[b+1]]-tls[lca]\]\(\sum_{v\in S[l,r]}d[v]\) 满足
\[\sum_{v\in S[l,r]}d[v]=tdrs[leafu[a-1]]-tdrs[lca]+tdls[leafu[b+1]]-tdls[lca]\]似乎以上部分都是可以使用 \(O(log)\) (寻找 \(lca\))来 \(O(1)\) 地解决问题,但是 \(ans\) 还有一个部分:
\[-\sum_{v\in S[l,r]}2\cdot d[lca(u,v)]\]这个部分能否使用树上差分呢?
答案是:肯定不行。
为什么?因为 \(v\) 在改变时,\(lca(u,v)\) 也在跟着改变。
那么怎么做?
分类讨论 \(u\) 的位置,这里就和我的暴力思路有点相像。
分以下几类:
先假设以 \(leafu[a-1]、leafu[b+1],lca\) 围成的树为 \(tre\)。
令 \(flca()\) 为寻找 \(lca\) 的算法。

  • \(u\) 在 \(tre\) 之外时。这样又要分两类
    - 当 \(u\) 是 \(lca\) 的祖先,那么一定满足\[\forall v\in S[l,r],flca(u,v)=u\]
    - 当 \(u\) 不是 \(lca\) 的祖先,那么一定满足\[\forall v\in S[l,r],flca(u,v)=lca(lca,u)\]
  • \(u\) 在 \(tre\) 之内时,对于这种情况需要自行推理。。。


另注:
可以发现,如果我们就这样建树的话,如果询问区间 \([1,n]\) 之类的区间就会出现问题,那么怎么解决?其实可以这样建图(以题目的树为例)

代码

没时间补题啊

原文地址:https://www.cnblogs.com/Arextre/p/12210539.html

时间: 2024-11-02 01:43:37

「CSP-S模拟赛」2019第一场的相关文章

「CSP-S模拟赛」2019第二场

目录 T1 Jam的计数法 题目 考场思路(正解) T2 「TJOI / HEOI2016」排序 题目 考场思路(假正解) 正解 T3 「THUWC 2017」随机二分图 题目 考场思路 正解 这场考试的数据感觉很水. \(T1\) 签到不解释,\(T2\) 期望 \(50pts\) 结果有 \(100pts\),\(T3\) 一如既往地不可做... ___ T1 Jam的计数法 题目 点这里 考场思路(正解) 其实没有什么好说的,找找规律即可,看看代码吧. #include<cstdio>

「2019-8-11提高模拟赛」女装盛宴 (flag)

传送门 Solution? 基环树+倍增+双指针 第一次因为#define int long long而玄学RE 为什么标程都不用开\(long long\)啊 Code? /*玄学RE 看来又是define ll long long 也有bug*/ #include<bits/stdc++.h> #define ll long long #define double #define dbg1(x) cerr<<#x<<"="<<(x)&

「csp校内训练 2019-10-24」解题报告

「csp校内训练 2019-10-24」解题报告 T1.猴猴吃苹果 \(Description\) 猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有 \(N \ (N \leq 50000)\) 个苹果,每个苹果有一个编号,分别为 \(0\) ~ \(N - 1\) 它们之间由 \(N-1\) 个树枝相连,猴猴可以从树枝的一端爬到树枝的另一端,所以猴猴可以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置. 猴猴开始在编号为 \(K \ (K < N)\) 的苹果的位置,并且把这个苹果吃

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

小王子「CSP多校联考 2019」

题意 又是一位被\(oi\)耽误了的文学家,甚至有一种做\(lxl\)题的感觉. 给定一棵树,向上加若干新边.现在可以删除一条树边一条新边,求将这棵树截断的方案数. 思路 对于一条边,如果没有新边覆盖他,显然删除这条边再删除任意一条新边均可. 如果有一条新边覆盖,那么删除这条树边再删除这条新边,只有一种方法. 否则不可能. 先把边转换为点然后跑一个树上差分即可. 原文地址:https://www.cnblogs.com/ilverene/p/11812885.html

python爬虫22 | 以后我再讲python「模拟登录」我就是狗

接下来就是 学习python的正确姿势 做爬虫 绕不开模拟登录 为此小帅b给大家支了几招 python爬虫19 | 遇到需要的登录的网站怎么办?用这3招轻松搞定! 有些网站的登录很弱鸡 传个用户名和密码 来个 POST 请求就搞定了 但还是少数 大多网站还是需要验证码的 登录需要验证码 频繁请求需要验证码 为此小帅b教你如何自动识别 python爬虫20 | 小帅b教你如何识别图片验证码 python爬虫21 | 对于b站这样的滑动验证码,不好意思,照样自动识别 当然了 市面上还有许多打码验证平

2019模拟赛09场解题报告

目录 2019模拟赛09场解题报告 目录la~~ 题一:瞬间移动 题二:食物订购 题三:马蹄印 题四:景观美化 2019模拟赛09场解题报告 标签(空格分隔): 解题报告 Forever_chen 2019.8.20 目录la~~ 题一:瞬间移动 [题面] 有一天,暮光闪闪突然对如何将一个整数序列a1,a2,...,an排序为一个不下降序列起了兴趣.身为一只年轻独角兽的她,只能进行一种叫做"单元转换"(unit shift)的操作.换句话说,她可以将序列的最后一个元素移动到它的起始位置

2019浙大计算机考研机试模拟赛(2)——概念专题

题目链接   引用自晴神OJ A - 边覆盖 B - 极大独立集 C - 稳定婚姻问题 D - 笛卡尔树 没赶得上全程的比赛,就做了两道,后面两道以后有时间再补.两道都是概念题,比较基础~ 以下是题解 A - 边覆盖 Case Time Limit: 200 MS (Others) / 400 MS (Java)       Case Memory Limit: 256 MB (Others) / 512 MB (Java) Accepted: 199      Total Submission

「十二省联考 2019」字符串问题

「十二省联考 2019」字符串问题 解题思路 傻逼题.. 考虑问题转化为一个A串向其支配的所有B串的后缀A串连边,如果有环答案 \(-1\) 否则是这个 \(\text{DAG}\) 上最长路径,直接建图是 \(n^2\) 的,考虑优化建图即可. 由于 \(A,B\) 都是原串的一个子串,那么对原串的反串建 SAM,一个子串的后缀就是其所在节点上比它长的串以及,其子树里的所有串. 首先将所有 \(A,B\) 串在 SAM上用倍增定位并新建节点,把SAM上每个节点拆成入点和出点,对于SAM每一个节