Codeforces Round 926 (Div. 2)

A

最终结果是 $a_n – a_1$,求下最大值最小值就好.

#include<bits/stdc++.h>
using namespace std;
#define LL long long
int t,n,maxn,minn;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n;
        maxn=-1; minn=1e9+10;
        for(int i=1,x;i<=n;i++) {
            cin>>x;
            minn=min(x,minn); maxn=max(x,maxn);
        }
        cout<<maxn-minn<<"\n";
    }
    return 0;
}

B

画图大概感受一下,发现每个格子可以提供 $2$ 条对角线。注意一下边界特判.

#include<bits/stdc++.h>
using namespace std;
#define LL long long
int t,n,k;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n>>k;
        if(k <= 4*n-4) cout<<(k+1)/2<<"\n";
        if(k == 4*n-3) cout<<2*n-1<<"\n";
        if(k == 4*n-2) cout<<2*n<<"\n";
    }
    return 0;
}

C

设 $f_i$ 为第 $i$ 回合最小下注钱数,因为第 $i$ 回合赢钱后不能比先前输的总钱数多,所以有

$b_i (k-1) > \sum_{j=1}^{i-1}b_j $

$b_i \geq \lfloor \frac{\sum_{j=1}^{i-1}b_j} {k-1} \rfloor+1$

注意循环过程中 $b_i$ 的和需要不大于 $a$.

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL t,k,x,a;
bool solve() {
    LL y=0,sum=0;
    for(int i=1;i<=x+1;i++) {
        y=1ll+(sum/(k-1ll));
        sum+=1ll*y;
        if(sum > a) return false;
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>k>>x>>a;
        if(solve()) cout<<"Yes\n";
        else cout<<"No\n";
    }
    return 0;
}

D

考虑dp.设 $dp_{i,j}$ 表示以 $x$ 为根节点的子树中,从根节点到叶子结点最多经过 $j$ 个危险节点的方案数.转移方程为

$dp_{x,1} = \prod_{y\in Son(x)}(dp_{y,1}+1)$

$dp_{x,2} = \sum_{y\in Son(x)}(dp_{y,1}+dp_{y,2})$

最后答案为 $1+dp_{i,1}+dp_{i,2} $.

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define int long long
const LL P = 998244353;
const int N=3e5+10;
struct Tree{
    int t,nex;
} e[N*2]; int tot,head[N];
void add(int u,int v) {
    e[++tot].t=v; e[tot].nex=head[u]; head[u]=tot;
}
int t,n;
LL dp[N][3],ans;
void init() {
    tot=0;
    for(int i=1;i<=n;i++) dp[i][1]=1,dp[i][2]=0,head[i]=0,e[i].nex=0,e[i+n].nex=0;
    ans=0;
}
void dfs(int x,int fath) {
    for(int i=head[x];i;i=e[i].nex) {
        int y=e[i].t;
        if(y == fath) continue;
        dfs(y,x);
        dp[x][1]*=(dp[y][1]+1ll)%P;
        dp[x][1]%=P;
        dp[x][2]+=dp[y][1]+dp[y][2];
        dp[x][2]%=P;
    }
    return;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n;
        init();
        for(int i=1,u,v;i<n;i++) {
            cin>>u>>v;
            add(u,v); add(v,u);
        }
        dfs(1,0);
        cout<<(dp[1][1]+dp[1][2]+1ll)%P<<"\n";
    }
    return 0;
}

E

这个 $k$ 的范围看着就很状压,,,

设 $s_i$ 表示边 $i$ 能贡献的链的集合,$f_s$ 表示标记集合 $s$ 中所有边所要花费的最小代价,有状态转移方程

$ f_{s\cup s_i}=min \{ f_{s\cup s_i},f_s+1 \} $

复杂度为 $O(2^{k} n)$.

不太能过,考虑怎么优化。因为链只有 $k$条,每条边的贡献集合 $s_i$ 实际上会有很多重复,可以用 set去重,将复杂度降为 $O(2^{k} k)$.

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=1e5+10;
const int M=2e6+10;
const int Inf=1e9;
int t,n,k;
struct tree{
    int t,nex;
} e[N*2]; int head[N],tot;
void add(int u,int v) {
    e[++tot].t=v; e[tot].nex=head[u]; head[u]=tot;
}
int fa[N],f[N],dep[N],dp[M];
void init() {
    for(int i=0;i<=n;i++) e[i].nex=0,e[i+n].nex=0,head[i]=0,fa[i]=0,f[i]=0,dep[i]=0,dp[i]=Inf;
    tot=0;
}
void dfs(int x,int fath) {
    dep[x] = dep[fath] + 1;
    fa[x]=fath;
    for(int i=head[x];i;i=e[i].nex) {
        int y=e[i].t;
        if(y == fath) continue;
        dfs(y,x);
    }
    return;
}
set<int> s;
void solve() {
    s.clear();
    dfs(1,0);
    cin>>k;
    for(int i=0;i< 1<<k;i++) dp[i]=Inf;
    for(int i=1,x,y;i<=k;i++) {
        cin>>x>>y;
        if(dep[x] < dep[y]) swap(x,y);
        while(dep[x] > dep[y]) { f[x]|=(1<<(i-1)); x=fa[x];}
        while(x != y) {f[x]|=(1<<(i-1)); f[y]|=(1<<(i-1)); x=fa[x]; y=fa[y];}
    }
    for(int i=2;i<=n;i++) s.insert(f[i]);
    dp[0]=0;
    for(int i=0;i<(1<<k);i++) {
        for(auto c : s) {
            dp[i|c] = min(dp[i|c],dp[i]+1);
        }       
    }
    cout<<dp[(1<<k)-1]<<"\n";
    return;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n;
        init();
        for(int i=1,u,v;i<n;i++) {
            cin>>u>>v;
            add(u,v); add(v,u);
        }
        solve();
    }
    for(int i=1;i<=n;i++) i++;
    return 0;
}

F

没啥意思的题,老trick的堆叠.

先求出BST的中序遍历,根据BST的性质,它的中序遍历应该是单调不减的。所以我们可以利用这个性质向中序遍历里的每个连续-1段填数。原问题被转化为向一个长度为 $len$ 的空序列里填入 $[l,r]$ 中的数,使序列单调不下降.这个问题的答案为 $ \binom {r-l+len} {len} $. 证明暂略.

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define int long long
const int N=1e6+10;
const int Mod=998244353;
int T,n,C;
struct Tree{
    int l,r,val;
} t[N];
int a[N],cnt;
void dfs(int x) {
    if(t[x].l != -1) dfs(t[x].l);
    a[++cnt]=t[x].val;
    if(t[x].r != -1) dfs(t[x].r);
    return;
}
int inv(int bs,int num=Mod-2){
    int res=1; 
    for(;num;num/=2){
        if(num & 1) res=(res*bs)%Mod;
        bs=(bs*bs)%Mod;
    } 
    return res;
}
int calc(int x,int y){
    int up=1,dn=1;
    for(int i=0;i<y;++i){
        up=up*(x-i)%Mod;
        dn=dn*(i+1)%Mod;
    } 
    return up*inv(dn)%Mod;
}
void solve() {
    cnt=0;
    dfs(1);
    a[0]=1; a[n+1]=C;
    LL ans=1;
    for(int i=1,l,r;i<=n;i++) {
        if(a[i] == -1) {
            l=i; r=i;
            for(;i<=n;i++) if(a[i] == -1) r=i; else break;
            ans*=calc(a[r+1]-a[l-1]+r-l+1,r-l+1);
            ans%=Mod;
        }
    }
    cout<<ans<<"\n";
    return;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>T;
    while(T--) {
        cin>>n>>C;
        for(int i=1,ll,rr,vv;i<=n;i++) {
            cin>>ll>>rr>>vv;
            t[i].l=ll; t[i].r=rr; t[i].val=vv;
        }
        solve();
    }
    for(int i=1;i<=100;i++) i++;
    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇