首页 > 其他分享 >【考后总结】9 月 CSP-S 模拟赛 2

【考后总结】9 月 CSP-S 模拟赛 2

时间:2023-09-10 18:11:53浏览次数:35  
标签:cnt 考后 int 存档 else edge maxn CSP 模拟

9.10 CSP 模拟 34

T1 斐波那契数

由于边权只有 \(\{0,1\}\),因此生成树的边权和取值连续,求出最小和最大判断即可。

点击查看代码
int t;
int n,m;

struct edge{
    int u,v,w;
    edge()=default;
    edge(int u_,int v_,int w_):u(u_),v(v_),w(w_){}
}e[maxn];

int bel[maxn];
int find(int x){
    if(x==bel[x]) return x;
    else return bel[x]=find(bel[x]);
}
inline int Kruskal1(){
    for(int i=1;i<=n;++i) bel[i]=i;
    sort(e+1,e+m+1,[&](edge A,edge B){
        return A.w<B.w;
    });
    int cnt=0,sum=0;
    for(int i=1;i<=m;++i){
        int u=e[i].u,v=e[i].v,w=e[i].w;
        int fu=find(u),fv=find(v);
        if(fu==fv) continue;
        bel[fv]=fu;
        ++cnt,sum+=w;
    }
    if(cnt!=n-1) return n+1;
    return sum;
}
inline int Kruskal2(){
    for(int i=1;i<=n;++i) bel[i]=i;
    sort(e+1,e+m+1,[&](edge A,edge B){
        return A.w>B.w;
    });
    int cnt=0,sum=0;
    for(int i=1;i<=m;++i){
        int u=e[i].u,v=e[i].v,w=e[i].w;
        int fu=find(u),fv=find(v);
        if(fu==fv) continue;
        bel[fv]=fu;
        ++cnt,sum+=w;
    }
    return sum;
}
int f[30];

int main(){
    t=read();
    while(t--){
        n=read(),m=read();
        for(int i=1,u,v,w;i<=m;++i){
            u=read(),v=read(),w=read();
            e[i]=edge(u,v,w);
        }
        int l=Kruskal1(),r=Kruskal2();
        printf("%d %d\n",l,r);
        bool chk=false;
        f[1]=1,f[2]=1;
        for(int i=1;i<=26;++i){
            if(i>=3) f[i]=f[i-1]+f[i-2];
            if(l<=f[i]&&f[i]<=r) chk=true; 
        }
        if(chk) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

T2 期末考试

判断 \(S\) 是否合法,即判断是否对于所有 \(i\),有 \(|S\cap T_i|=a_i\)。

发现 \(O(4^10n)\) 不能接受,但 \(O(4^5n)\) 是可以的。分成前后两半形如 \(f(S_1,i)+g(S_2,i)=a_i\),可以把 \(f(S_1)\) 哈希存入 map,对于每个 \(g(S_2)\) 可以求出希望得到的 \(f\),查询个数即可。

点击查看代码
struct Data{
    int k;
    Data()=default;
    Data(int k_):k(k_){}
    int operator&(const Data &rhs)const{
        int res=0;
        for(int i=1;i<=5;++i){
            int now=3<<2*(i-1);
            if((k&now)==(rhs.k&now)) ++res;
        }
        return res;
    }
};

int t;
int n;
Data T[maxn][2];
int a[maxn];
char ch[12];
int g[maxs][maxn];
map<int,int> mp;
int ans;

int main(){
    t=read();
    while(t--){
        n=read();
        for(int i=1;i<=n;++i){
            scanf("%s",ch+1);
            a[i]=read()/10;
            T[i][0].k=T[i][1].k=0;
            for(int j=1;j<=5;++j){ 
                T[i][0].k|=(ch[j]-'A')<<2*(j-1);
                T[i][1].k|=(ch[j+5]-'A')<<2*(j-1);
            }
        }
        mp.clear();
        for(int s=0;s<(1<<10);++s){
            int h=0;
            for(int i=1;i<=n;++i){
                int now=Data(s)&T[i][0].k;
                h=(1ll*h*base%mod+now)%mod;
            }
            ++mp[h];
        }
        ans=0;
        for(int s=0;s<(1<<10);++s){
            int h=0;
            for(int i=1;i<=n;++i){
                int now=a[i]-(Data(s)&T[i][1].k);
                h=(1ll*h*base%mod+now)%mod;
            }
            ans+=mp[h];
        }
        printf("%d\n",ans);
    }
    return 0;
}

T3 麻烦的工作

贪心,任务按所需人数降序排序,优先安排人数较多的。证明似乎可以考虑拟阵(以后应该会学)。

那么就是对于每个 \(i\),判断是否:

\[\sum_{j=1}^m \min(i,b_j)\ge \sum_{i=1^n} a_i \]

左侧可以套路转化成设 \(c_i\) 表示不小于 \(i\) 的 \(b_j\) 个数,变成:

\[\sum_{i=1}^n c_i-\sum_{i=1}^n a_i\ge 0 \]

线段树维护。

修改 \(b\) 是平凡的后缀加减,修改 \(a\) 时要求降序,因此如果增加则修改第一个,如果减少则修改最后一个。

点击查看代码
int n,m,q;
int a[maxn],b[maxn],c[maxn];
int id[maxn],sum[maxn];
int L[maxn],R[maxn];
struct SegmentTree{
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
    int mn[maxn<<2];
    int tag[maxn<<2];
    inline void push_up(int rt){
        mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
    }
    inline void push_down(int rt){
        if(tag[rt]){
            mn[rt<<1]+=tag[rt],tag[rt<<1]+=tag[rt];
            mn[rt<<1|1]+=tag[rt],tag[rt<<1|1]+=tag[rt];
            tag[rt]=0;
        }
    }
    void build(int rt,int l,int r){
        tag[rt]=0;
        if(l==r) return mn[rt]=c[l]-sum[l],void();
        build(lson),build(rson);
        push_up(rt);
    }
    void update_range_add(int rt,int l,int r,int pl,int pr,int k){
        if(pl<=l&&r<=pr){
            mn[rt]+=k,tag[rt]+=k;
            return;
        }
        push_down(rt);
        if(pl<=mid) update_range_add(lson,pl,pr,k);
        if(pr>mid) update_range_add(rson,pl,pr,k);
        push_up(rt);
    }
#undef mid
#undef lson
#undef rson
}S;

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read(),id[i]=i;
    sort(id+1,id+n+1,[&](int A,int B){
        return a[A]>a[B];
    });
    for(int i=1;i<=m;++i){
        b[i]=read();
        ++c[1],--c[b[i]+1];
    }
    for(int i=1;i<=n;++i) c[i]+=c[i-1];
    for(int i=1;i<=n;++i){
        ++R[a[i]];
        sum[i]=sum[i-1]+a[id[i]],c[i]+=c[i-1];
    }
    int now=0;
    for(int i=lim;i>=0;--i){
        if(R[i]) L[i]=now+1,R[i]+=now,now=R[i];
        else L[i]=R[i]=0;
    }
    S.build(1,1,n);
    q=read();
    while(q--){
        int opt=read(),x=read();
        if(opt==1){
            int p=L[a[x]];
            S.update_range_add(1,1,n,p,n,-1);
            if(L[a[x]]==R[a[x]]) L[a[x]]=R[a[x]]=0;
            else ++L[a[x]];
            ++a[x];
            if(!L[a[x]]&&!R[a[x]]) L[a[x]]=R[a[x]]=p;
            else ++R[a[x]];
        }
        else if(opt==2){
            int p=R[a[x]];
            S.update_range_add(1,1,n,p,n,1);
            if(L[a[x]]==R[a[x]]) L[a[x]]=R[a[x]]=0;
            else --R[a[x]];
            --a[x];
            if(!L[a[x]]&&!R[a[x]]) L[a[x]]=R[a[x]]=p;
            else --L[a[x]];
        }
        else if(opt==3){
            ++b[x];
            if(b[x]<=n) S.update_range_add(1,1,n,b[x],n,1);
        }
        else{
            if(b[x]<=n) S.update_range_add(1,1,n,b[x],n,-1);
            --b[x];
        }
        printf("%d\n",(S.mn[1]>=0));
    }
    return 0;
}

T4 小 X 的 Galgame

策略应当为将 \(u\) 存档时,一次性去到所有应当去到的叶子,再去被 \(u\) 子树内其他节点存档时覆盖的叶子,反过来考虑就是每个叶子是在到根路径上第一个节点 \(u\) 存档时被去到的。

可以将 \(1\) 看作被存档,而如果一个节点没有存档,但子树内和祖先都存在存档点,那么这个节点是否存档没有影响,不妨看作存档。

这样存档的节点实际是原树删去一些叶子部分的子树剩余的全部子树,根据这个性质,DP 变得容易。

设 \(f_u\) 表示 \(u\) 子树没有存档的最小代价,实际就是 \(u\) 到所有叶子距离之和,\(g_u\) 表示 \(u\) 子树被存档的最小代价。

设 \(cnt_u\) 为 \(u\) 子树内的叶子个数,那么 \(f_u\) 转移是容易的。

\(g_u\) 转移是讨论儿子 \(v\) 有没有存档,没有存档即 \(cnt_u\times w(u,v)+g_v\),有存档即 \(\mathrm{dist}(1,v)+f_v\)。

注意到在实际过程中,存在一个有存档的 \(v\),是直接从 \(u\) 而不是 \(1\) 出发的,相当于如果存在有存档的 \(v\),那么最终 \(g_u\) 应当减去 \(\mathrm{dist}(1,u)\)。这部分可以特殊处理,具体只需要维护差值的最小值,判断是否存在有存档的 \(v\) 或者将一个不存档的替换成有存档的来减去 \(\mathrm{dist}(1,u)\) 会不会更优。

点击查看代码
int n;
struct edge{
    int v,w;
    edge()=default;
    edge(int v_,int w_):v(v_),w(w_){}
};
vector<edge> E[maxn];

ll dis[maxn];
ll f[maxn],g[maxn];
int cnt[maxn];
void dfs(int u,int fa){
    if(u!=1&&(int)E[u].size()==1) return cnt[u]=1,void();
    for(edge e:E[u]){
        int v=e.v,w=e.w;
        if(v==fa) continue;
        dis[v]=dis[u]+w;
        dfs(v,u);
        cnt[u]+=cnt[v];
    }
    ll mn=llinf;
    for(edge e:E[u]){
        int v=e.v,w=e.w;
        if(v==fa) continue;
        f[u]+=f[v]+1ll*w*cnt[v];
        g[u]+=min(f[v]+1ll*w*cnt[v],g[v]+dis[v]);
        mn=min(mn,(g[v]+dis[v])-(f[v]+1ll*w*cnt[v]));
    }
    if(mn<0) g[u]-=dis[u];
    else if(mn<dis[u]) g[u]+=mn-dis[u];
}

int main(){
    n=read();
    for(int i=1,u,v,w;i<n;++i){
        u=read(),v=read(),w=read();
        E[u].push_back(edge(v,w)),E[v].push_back(edge(u,w));
    }
    dfs(1,0);
    printf("%lld\n",g[1]);
    return 0;
}

标签:cnt,考后,int,存档,else,edge,maxn,CSP,模拟
From: https://www.cnblogs.com/SoyTony/p/Simulation_Problems_of_CSP-S_in_September_2.html

相关文章

  • monkey解决adb devices识别不到夜神模拟器问题
    一、输入命令检测不到,确认夜神模拟器是否开启了调试模式 二、如果夜神模拟器已经打开调试模式了,但使用adbdevices还是找不到设备,可以输入adbconnect127.0.0.1:62001连接上夜神模拟器(62001为夜神模拟器的端口号)。但此方法只适用当前会话,想要从根本上解决见下面方法。三、sdk......
  • 9.9模拟总结
    模拟赛笔G总体上:这一次考试真的是dp专场,我全部打的暴力部分分,难受的一批!主要是我个人的dp能力太薄弱了......个体上:第一题:在考场上我的状态设计的很正确,但是没有想出正解,也没有想到过单调队列优化这些事。总结:dp的优化除了直接时间上优化,还可以通过减少状态数来优化。就......
  • CSP 2020 第一轮(初赛)模拟解析
    一、十进制数\(114\)的相反数的\(8\)位二进制补码是:A.\(10001110\)$\\\\\$B.\(10001101\) $\\\\\$C.\(01110010\) $\\\\\$D.\(01110011\)点击查看答案根据原码补码反码的有关定义可得:-114的源码为:01110010反码为:10001101......
  • 九月做题记录(距 CSP 还有 1 个月)
    P3959[NOIP2017提高组]宝藏发现\(n\)是很小的,考虑状压。我们先记录下当前的树包含了哪些节点,然后因为转移时肯定会需要经过了多少边,也就是树的深度。我们记录\(\text{expand(i)}\)表示当前选的集合为\(i\)时,扩展一次后的集合。\(\text{road(i,j)}\)表示选的集合为......
  • 数组模拟链表 模拟栈和队列 单调栈和队列(9/7 9/8)
    单链表数组模拟链表可以加快速度,更利于优化算法#include<iostream>usingnamespacestd;constintN=100010;inte[N],ne[N],head,idx;voidinit(){head=-1;idx=0;}voidadd_head(intx){e[idx]=x;ne[idx]=head;head=idx++;}void......
  • 记PE文件结构实验,模拟文件内存加载过程。
    记录文件结构试验前言:使用的模拟程序是notepad.exe,主要记录其中的思路和遇到其中的困难。实验目的:模拟内存加载PE文件的过程,将每个区段模拟加载到内存之中。根据文件结构中头表中的信息,读取并sekk指针到Segment头。然后循环遍历Segment头将内容加载到VirtualAddress中,主要目的......
  • DHCP饿死攻击及防御(基于ENSP模拟器、Kali攻击机实现)
    相关参数:·Kali攻击机一台·ENSP模拟器 拓扑图:   实验说明:·通过配置DHCP_Server,使得192.168.150.0/24子网内的终端能够自动获取IP地址及DNS·通过配置SW交换机,开启DHCPSnooping功能,用于保证DHCP客户端从合法的DHCP服务器获取IP地址·Kali攻......
  • python模拟用户登录
    python模拟用户登录目录python模拟用户登录一、授权认证二、Cookie认证一、授权认证1、HTTP基础认证importrequestsfromrequests.authimportHTTPBasicAuthurl="https://xxx.xxx.xxx/"username="admin"password="admin"#HTTP基础认证response=requests.ge......
  • wzOI 2023.8.24 模拟赛(附树的直径和三分法)
    2023-08-2815:53:53$$A$$典型错误一知半解看样例型:如果该队某个数组的值比最大值大就算入答案。上第一次厕所前我的思路:开局\(30\)分钟。显然,我并不需要有一个数值最大才能赢,我只需要其中一个数值比其中一个数值比其中一个数值最大的那个要大的队要大即有可能获胜......
  • 暑假集训 Day17 模拟赛题解
    2023-08-0318:18:03前言好家伙,很少完整订正一场比赛,可能是因为这个比赛相对来说确实不难吧(至少正解不难)。总结与反思这场比赛其实没有我想象的那么难,只是觉得题目可能不简单,就没有往简单的思路想,反而是被之前讲过的题疑惑,以为要用到一些很奇特的算法,结果打完以后看了题解再结......