首页 > 其他分享 >Codeforces Round 986 (Div. 2)

Codeforces Round 986 (Div. 2)

时间:2024-11-15 12:40:16浏览次数:1  
标签:int ll 986 Codeforces down ans Div now dp

AB

没什么好说的。

C

把我卡了。dp非常明显,最开始我想的是单向做,\(f[i][0/1]\)表示前\(i\)块蛋糕已经分出去了,01表示Alice是否拿过了,此时分给了几个人。
尝试写写转移就知道为什么寄了。状态不够,没法表示答案。就算转移到了最后也没法得出我们需要的答案。可以发现,这个dp不好做的原因就是alice取蛋糕的部分并不确定。

赛时的时候没有转换思路,非常笃定这是dp。但是其实做到这里dp就已经被叉了。这个dp方程的形式已经没有优化的机会了。如果要写出正确的暴力dp方程,需要3维,其中光空间就\(n*m\),而这个状态和转移不满足任何优化的形式。就算满足了,写个2C用斜率优化之类的也挺离谱的。。

事实上这是一个贪心。其实很容易发现,我们的操作里面并不存在“舍弃一块蛋糕”这种操作。假如不考虑alice,那这个题目就是扫一遍就能出答案。考虑一下答案的结构,其实一定是左边一段给客人,右边一段给客人,中间alice拿一段。给客人的直接贪心是有固定答案的,所以其实直接枚举就可以了。思考一下可以发现单调性非常明显,固定一个端点二分或者倍增另一个端点就结束了。

其实会被卡,很大一部分是因为开始看错题了。意外是alice必须取最后一段。那就是一个挺裸的dp?好吧,贪心。我居然写了二分??无敌了。
有点抽象的。这种错误。

D

这题是真恶心。
很明显,只能顺序取,那就直接顺序枚举每个点,然后看每个人是不是有价值更高的卡牌在之前能够得到。这个玩意,树状数组就能够做到,单点修改然后区间查询嘛。但是要求方案。值域树状数组不是那么好搞。迫不得已还写了线段树。。
一眼秒了,还让我写上百行。无敌了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
int n,a[200001],b[200001],c[2000001];
int f[200001][2];
inline int ls(int x){
    return (x<<1);
}
inline int rs(int x){
    return (x<<1)|1;
}
struct Seg_Tree
{
    int val[8000001],From[8000001];
    inline void push_up(int p)
    {
        if(val[ls(p)]==0&&val[rs(p)]==0)
        {
            val[p]=0;
            From[p]=0;
            return ;
        }
        if(val[ls(p)]>=val[rs(p)])
        {
            val[p]=val[ls(p)];
            From[p]=From[ls(p)];
        }
        else 
        {
            val[p]=val[rs(p)];
            From[p]=From[rs(p)];
        }
    }
    void build(int p,int l,int r)
    {
        if(l==r)
        {
            val[p]=0;From[p]=0;
            return ;
        }
        int mid=l+r>>1;
        build(ls(p),l,mid);
        build(rs(p),mid+1,r);
        push_up(p);
    }
    void change(int p,int l,int r,int tar,int x,int Fa)
    {
        if(l==r&&l==tar)
        {
            val[p]=x;
            From[p]=Fa;
            return;
        }
        int mid=l+r>>1;
        if(tar<=mid)change(ls(p),l,mid,tar,x,Fa);
        if(tar>mid)change(rs(p),mid+1,r,tar,x,Fa);
        push_up(p);
    }
    int query(int p,int l,int r,int tl,int tr)
    {
        if(tl<=l&&r<=tr)
        {
            return From[p];
        }
        int mid=l+r>>1;
        int ans=0;
        if(tl<=mid)ans=max(ans,query(ls(p),l,mid,tl,tr));
        if(tr>mid)ans=max(ans,query(rs(p),mid+1,r,tl,tr));
        return ans;
    }
}A,B,C;
int main()
{
    int T=read();
    while(T--)
    {
        n=read();
        for(int i=1;i<=n;i++)f[i][0]=f[i][1]=0;
        for(int i=1;i<=n;i++)
            a[i]=read();
        for(int i=1;i<=n;i++)
            b[i]=read();
        for(int i=1;i<=n;i++)
            c[i]=read();
        f[1][0]=1;
        A.build(1,1,n);
        B.build(1,1,n);
        C.build(1,1,n);
        A.change(1,1,n,a[1],1,1);
        B.change(1,1,n,b[1],1,1);
        C.change(1,1,n,c[1],1,1);
        for(int i=2;i<=n;i++)
        {
            int a1=A.query(1,1,n,a[i],n);
            int b1=B.query(1,1,n,b[i],n);
            int c1=C.query(1,1,n,c[i],n);
            if(a1!=0)f[i][0]=1,f[i][1]=a1;
            else 
            if(b1!=0)f[i][0]=1,f[i][1]=b1;
            else 
            if(c1!=0)f[i][0]=1,f[i][1]=c1;
            if(f[i][0])
                A.change(1,1,n,a[i],1,i),
                B.change(1,1,n,b[i],1,i),
                C.change(1,1,n,c[i],1,i);
        }
        // cout<<'4'<<endl;
        if(!f[n][0])cout<<"No"<<'\n';
        else
        {
            cout<<"Yes\n";
            vector<pair<char,int>> ans;
            int now=n;
            while(now!=1)
            {
                int back=f[now][1];
                if(a[back]>a[now])
                    ans.push_back({'q',now});
                else
                if(b[back]>b[now])
                    ans.push_back({'k',now});
                else 
                    ans.push_back({'j',now});
                now=back;
            }
            cout<<ans.size()<<'\n';
            for(int i=ans.size()-1;i>=0;i--)
            {
                cout<<ans[i].first<<' '<<ans[i].second<<'\n';
            }
        }

    }
}

E

有点意思的题目。
其实先简单写写表达式,就能够发现是一个有后效性的转移方程。那其实说这是一个线性方程组更适合。
但是这个线性方程组的相关参数非常固定,全是\(\frac 1 2\),那就很可能不需要用高斯消元了。
需要先考虑一下两个人的行动策略。非常明显,alice一定是向根节点走的,而阻止她的人一定是让她往最近的叶子节点走的。
所以可以进行一个类似树剖的过程,把树剖成一个个链,剖的法则就是距离子树里面叶子最近的点剖在一条链上。
那么,如果一次行动的起始点在这个链上,那么,这次行动的结果很固定,要么走到链的头部,来到另一条链或者是终点,要么是被推到叶子节点。
所以我们可以把问题简化为在一根根不同长度的链上行动,然后把结果乘起来。
前面分析已经能得到了,这个方程是一个系数固定的线性方程组。会有变化的只有这个线性方程组的项数。可以考虑项数会带来哪些变化。
手玩了一下不同项的方程,其实就能得到通解了。(虽然如果做的熟练的话,这个玩意看到的第一眼就知道是有一个和项数相关的通解的表示的)
对于一个在长度为\(d\)的链上的从上往下数第\(i\)个位置,从这里走到链首的概率是\(1-\frac {i-1}d\)
如果这题改改,p不是\(1/2\),其实也能做,也是推到一下能得到通解,需要高斯消元解方程的是对于每个点\(p\)都不一样。

然后这题就没有了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read()
{
    char c=getchar();ll a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
    return a*b;
}
const ll Mod=998244353;
ll n;
struct edge
{
    ll next,to;
}e[400001];
ll head[400001],tot,leaf[200001],down[200001][2],dep[200001];
inline void add(ll i,ll j)
{
    e[++tot].next=head[i];
    e[tot].to=j;
    head[i]=tot;
}
ll ksm(ll x,ll a)
{
    if(a==0)return 1;
    if(a==1)return x;
    if(a==2)return x*x;
    if(a%2==0)
    {
        ll ans=ksm(x,a/2)%Mod;
        ans=ans*ans%Mod;
        return ans;
    }
    else 
    {
        ll ans=ksm(x,a/2)%Mod;
        ans=ans*ans%Mod*x%Mod;
        return ans;
    }
}
ll ans[2000001];
pair<ll,ll> dfs(ll x,ll fa)
{
    dep[x]=dep[fa]+1;
    ll cnt=0;
    down[x][0]=0x3f3f3f3f;
    for(ll i=head[x];i!=0;i=e[i].next)
    {
        ll u=e[i].to;
        if(u==fa)continue;
        cnt++;pair<ll,ll> Ned=dfs(u,x);
        if(down[x][0]>Ned.first+1)
        down[x][0]=Ned.first+1,down[x][1]=Ned.second;

    }
    if(cnt==0)leaf[x]=1,down[x][0]=0,down[x][1]=x;
    else leaf[x]=0;
    return {down[x][0],down[x][1]};
}
void dfs_ans(ll x,ll fa,ll now,ll up)
{
    // if(leaf[x])ans[x]=0;
    ll len=dep[down[x][1]]-dep[up];
    ll now_place=dep[x]-dep[up]+1;
    ans[x]=ans[now]*(len-now_place+1)%Mod*ksm(len,Mod-2)%Mod;
    for(ll i=head[x];i!=0;i=e[i].next)
    {
        ll u=e[i].to;
        if(u==fa)continue;
        if(down[u][1]==down[x][1])
            dfs_ans(u,x,now,up);
        else
            dfs_ans(u,x,x,x);
    }
}
int main()
{
    ll T=read();
    while(T--)
    {
        n=read();
        for(ll i=0;i<=tot;i++)head[i]=0;tot=0;
        for(ll i=1;i<n;i++)
        {
            ll x=read(),y=read();
            add(x,y);add(y,x);
        }
        dfs(1,0);
        ans[1]=1;
        dfs_ans(1,0,1,1);
        // cout<<1<<endl;
        for(ll i=1;i<=n;i++)
        {
            cout<<ans[i]%Mod<<' ';
        }
        cout<<'\n';
    }
    return 0;
}

标签:int,ll,986,Codeforces,down,ans,Div,now,dp
From: https://www.cnblogs.com/HLZZPawa/p/18547745

相关文章

  • 第九章 DIV+CSS布局
    9.1DIV+CSS概述9.1.1认识DIVdiv标签在Web标准的网页中使用非常频繁,属于块状元素。div标签是双标签,即以<div></div>的形式存在,中间可以放置任何内容,包括其他的div标签。但是在没有CSS的影响下,每个div标签只占据一行,即一行只能容纳一个div标签。9.1.2DIV的宽高设置对div......
  • Solution - Codeforces 1681E Labyrinth Adventures
    能够发现这个最短路的形态一定是从低层一层一层走到高层的。那么这就说明若起点终点对应层数为\(x,y\)。若\(x=y\)则直接算,就是曼哈顿距离。否则不妨钦定\(x<y\)(不满足就交换,不影响结果),那么层数\(z\in[x,y)\)的其中一个门肯定都会被经过。于是考虑把\(\operator......
  • Solution - Codeforces 1190C Tokitsukaze and Duel
    考虑到两人对应的操作是相同的,于是可以从对称的角度来思考。考虑到在先手做出操作后,后手一个较为特殊的操作是不做任何影响,也就是重复先手的操作。能够发现如果对于后手这不能必胜,那么他一定不会去产生影响,并又把这个局面留给先手,相当于是先后手的交换。对于先手又是同样的,因为......
  • 第九章DIV+CSS布局
    9.1DIV+CSS概述    DIV+CSS是Web设计标准,它是一种网页的布局方法。与传统中通过表格(table)布局定位的方式不同,它可以实现网页页面内容与表现相分离。DIV组成了网页的格局,CSS 则装饰了格局,比如建一栋房子,开始的架子是DIV,架子搭建好后开始装饰,这个装饰就是CSS样式。用......
  • CodeCraft-21 and Codeforces Round 711 (Div. 2) F. Christmas Game【阶梯博弈、换根
    这道题目是比较经典的树上阶梯博弈。设一个点的深度是\(dep_i\),如果两个点\(i,j\)满足\(dep_i\not\equivdep_j\modk\),则两个点对答案的影响是完全独立的。我们可以把图拆分为\(k\)部分,并且按照原图中的祖先关系把新图连接为\(k\)棵树。对于一个点\(i\),在新图中的深度为\(dep_......
  • B. Alice's Adventures in Permuting (python解)-codeforces
    B.Alice'sAdventuresinPermuting(python解)-codeforces原题链接:B.Alice'sAdventuresinPermuting问题分析:我们需要将数组a转换为一个排列,排列是由n个不同的整数构成,范围从0到n−1。数组a是通过给定的参数n、b和c生成的。\[a[i]=b⋅(i−1)+c\]\[对于1≤i......
  • CF983-Div.2-E
    CF983-Div.2-E自己独立完成的一道蓝题!中间思路有很多想复杂了的地方,但最终还是做出来了!记录一下自己的心路历程。手玩样例找思路狂搓4个样例!搓到第4个,把每个位置操作完之后的序列都写下来观察,写的过程中猛然发现数和数之间的操作有一种一环扣一环的感觉,如果按顺序操作,上一个操......
  • 「AT_diverta2019_2_e」Balanced Piles 题解
    题意描述有一个长度为\(N(2\leN\le10^6)\)的数组,一开始所有元素均为\(0\)。设\(M\)为当前数组中的最大元素,\(m\)是当前数组中的最小元素,你可以执行若干次以下操作:选择一个大小为\(m\)的元素,把他变为\(x\),其中\(M\lex\leM+D\)且\(m<x\)。求有多少种操作方法......
  • Educational Codeforces Round 157 (Rated for Div. 2) - VP 记录
    Preface啊啊啊为什么我老是被简单题卡啊!A.TreasureChestA题题面这么长吓我一跳。分类讨论,钥匙在前面可以拿了钥匙直接到箱子那里;箱子在前面就尽量把箱子往钥匙搬,让折回的距离尽量小。点击查看代码#include<cstdio>#include<algorithm>usingnamespacestd;intmain......
  • Codeforces Round 985 div1+2 个人题解(A~E)
    CodeforcesRound985div1+2个人题解(A~E)Dashboard-Refact.aiMatch1(CodeforcesRound985)-Codeforces火车头#include<bits/stdc++.h>usingnamespacestd;#defineftfirst#definesdsecond#defineyescout<<"yes\n"#definenoc......