Codeforces 每日一练 855C+1172A+1151C

855C Helga Hufflepuff’s Cup

传送门
题意:对一棵树上的n个点染色,有m种颜色,对于颜色k,最多染x个,并且每一个与颜色为k的节点相连的点的颜色必须小于k
很明显是一道树形dp的题啦,一开始只开了二维,记录取k/不取k,发现转移不动,然后意识到每个节点有三种情况:取k,小于k,大于k,并且我们还要记录当前有几个节点颜色为k,并且已经限定了x≤10,自然开三维去转移就好,比如dp[i][j][l]就代表第i个节点染色情况为j时有l个节点颜色为k的情况数。
但是考虑到每加入一棵子树时应该是与当前答案相乘的关系,所以在转移时要记录每次加入的答案,然后相乘处理。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
#define il inline
#define mod 1000000007
vector<int> g[maxn];
ll dp[maxn][3][15];
int n,num;
ll m,k;
void dfs(int x,int fa){
    dp[x][0][0]=k-1;
    dp[x][2][0]=m-k;
    dp[x][1][1]=1;
    for(auto i:g[x]){
         if(i!=fa){
             dfs(i,x);
             ll tmp[15][3]={0};
             for (int j = 0; j <=num ; ++j) {
                 for (int l = 0; l <=j ; ++l) {
                     tmp[j][0]+=(dp[i][0][l]+dp[i][1][l]+dp[i][2][l])*dp[x][0][j-l];
                     tmp[j][0]%=mod;
                     tmp[j][1]+=dp[i][0][l]*dp[x][1][j-l];
                     tmp[j][1]%=mod;
                     tmp[j][2]+=(dp[i][2][l]+dp[i][0][l])*dp[x][2][j-l];
                     tmp[j][2]%=mod;
                 }
             }
             for (int j = 0; j <=num ; ++j) {
                 dp[x][0][j]=tmp[j][0];
                 dp[x][1][j]=tmp[j][1];
                 dp[x][2][j]=tmp[j][2];
             }
         }
    }
}
int main() {
    int x;
    cin>>n>>m;
    for (int i = 0; i <n-1 ; ++i) {
        int u,v;
        cin>>u>>v;
        g[v].push_back(u);
        g[u].push_back(v);
    }
    cin>>k>>x;
    num=x;
    dfs(1,0);
    ll ans=0;
    for (int i = 0; i <=x ; ++i) {
        ans+=dp[1][2][i]+dp[1][0][i]+dp[1][1][i];
        ans%=mod;
    }
    cout<<ans%mod;
    return 0;
}

(貌似HDU也有一道类似思路的题)

1172A Nauuo and Cards

传送门
题意:你手里有n张牌,场上有n张牌,每张牌的值在0~n,每次可以从手中选择一张牌放在场上牌堆的最后,并且把第一张取走,询问最少多少次可以使得场上的顺序为1-n。
很明显答案是有上界的,最差就是把n张都取走,然后依次放置,而对于初始每一张牌,假设其值为i,位置为p[i],那么将其移动到正确位置需要p[i]-i+n+1次,显然取max(p[i]-i+n+1)次就可以完成目标。
但是仍然存在存在更优方案的情况,不如考虑1 2 3,如果我们按照上面的方法,是4,但是显然答案是0。很容易联想到如果我们可以1,2,3……n的放置,那么我们就没必要用上面的取法,而这种情况需要从场上的末尾开始向前存在i ,i-1,i-2,……1,并且我们每次可以把末尾牌面+1的牌放到末尾,此时需要的次数是小于上面的情况的。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 200005
#define mod 1000000007
#define rep(i,m,n) for(int (i)=(m);(i)<=(n);(i)++)
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int a[maxn],b[maxn];
int pos[maxn];
int main() {
    IOS
    int n;
    cin>>n;
    int ans=0;
    rep(i,1,n)cin>>a[i];
    rep(i,1,n){cin>>b[i];pos[b[i]]=i;}
    if(pos[1]!=0){
        int i;
        for (i = 2; pos[i]-pos[1]==i-1 ; ++i){}
        if(pos[i-1]==n){
            int j;
            for (j = i; j<=n&&pos[j]<=j-i ; ++j){}
            if(j>n){
                cout<<n-i+1;
                return 0;
            }
        }
    }
    rep(i,1,n)ans=max(ans,pos[i]-i+n+1);
    cout<<ans;
    return 0;
}

1151C Problem for Nazar

传送门
题意:每次从奇数列和偶数列取2的幂次个数写到黑板上,比如1 | 2 4 | 3 5 7 9 | 6 8 10……,询问区间[l,r]的和。
上午刚学了数位dp,直接就想到了前缀和相减的思路。对于前i个,虽然看起来计算挺麻烦,但是不难发现

  • 奇数列中,前i项和为i*i
  • 偶数列中,前i项和为i*(i+1)

那么我们只需要去找前i个数中有多少奇数和多少偶数就好了。
(日常瞎**取模wa了半天)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
#define mod 1000000007
ll calc(ll x){
    int cnt=1;
    ll l=1,lr=0ll,r=0ll;
    while(x>=l){
        int fl=0;
        if(cnt==1&&x>=l){
            fl=1;
            x-=l;
            lr+=l;
            l*=2;
        }else if(cnt==0&&x>=l){
            fl=1;
            x-=l;
            r+=l;
            l*=2;
        }
        cnt++;
        cnt%=2;
        if(!fl)break;
    }
    if(!cnt)r+=x;
    else lr+=x;
    lr%=mod;
    r%=mod;
    return ((lr*lr)%mod+(r*(r+1))%mod)%mod;
}
int main() {
    ll l,r;
    cin>>l>>r;
    cout<<((calc(r)-calc(l-1))%mod+mod)%mod;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我可以分享一种有效的训练计划,以达到codeforces橙名。首先,建立一个长期的训练计划,每周至少完成3-4个题目,把每个题目的解题过程都认真的思考一遍,确保理解每一步的思。建议每隔一段时间,做一次综合练习,以更好地检验自己的知识水平。此外,参加竞赛也可以加深对算法的理解,从而提升解题能力。 ### 回答2: 想要在Codeforces达到橙名的水平,需要进行系统性的训练,并掌握一定的算法和编程技巧。以下是一个可能的训练计划: 1. 学习基础知识:首先,建议你系统地学习计算机科学的基础知识,包括数据结构和算法。这可以帮助你理解不同问题的解决方案,并优化代码的执行效率。 2. 解决题目:开始刷题是锻炼算法和编码能力的关键。选择一些简单的题目,如Codeforces的Div2 A、B级题目,按难度逐渐增加。通过不断解决题目,你将熟悉各种算法,并提高编写清晰、高效代码的能力。 3. 学习算法:学习和掌握一些常用算法,如贪心、动态规划、图论等。理解算法原理,分析其时间和空间复杂度,并通过练习将其应用于具体的问题。 4. 参加比赛:参加Codeforces的比赛是衡量自己水平的好方法。开始参加Div2级别的比赛,并争取在中等难度的题目上取得好成绩。逐渐挑战3级、4级比赛,尽量与更强的选手竞争,以提高自己的水平。 5. 反思和学习:每次比赛后,对自己的解题过程进行反思和总结。分析解错的原因,学习其他参赛选手的思考方式和技巧。通过学习他人的优秀代码和解题思,不断提升自己的编码能力。 6. 练习编码技巧:除了算法,熟练掌握编码技巧也非常重要。学习并应用一些常用的数据结构和STL库,如数组、链表、栈、队列等。多写一些小项目或练习题,锻炼自己的编码能力。 7. 时间管理:合理安排学习和练习的时间。每天保持一定时间的刷题和学习,坚持养成好的学习习惯。同时,在比赛中也要控制好时间,并尽量在限定时间内完成题目。 总之,达到Codeforces橙名的水平需要长期的训练和不断的学习。通过刷题、学习算法和编码技巧、参加比赛以及反思总结,你可以逐渐提升自己的水平,并取得理想的成绩。记住,坚持和持续学习是达到目标的关键。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值