Codecraft-18 and Codeforces Round #458 C dp D 线段树

Codecraft-18 and Codeforces Round #458

C. Travelling Salesman and Special Numbers

题意: 一个由0、1 组成的数 n,操作:n 有 m 个 1,就把 n 变为 m。 问 <=n 的数中有多少个恰好经过 k 次操作能变为 1。

tags:  dp[i][j] 表示长度为 i 且有 j 个 1  的串,比对应的 n 要小的方案数。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 1005, mod = 1e9+7;

ll  k, ans1[N], cnt, len;
char s[N];
ll  get(int x)  {
    ll  sum = 0;
    while(x) {
        if(x&1) ++sum;
        x >>= 1;
    }
    return sum;
}
ll  dp[N][N], C[N][N];
void Init()
{
    C[1][0] = C[1][1] = 1;
    rep(i,2,N-1)
    {
        C[i][0] = 1;
        rep(j,1,N-1)
            C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
    }

    if(s[len]==‘1‘) dp[len][1]=dp[len][0]=1;
    else dp[len][1]=0, dp[len][0]=1;
    per(i,len-1,1)
    {
        dp[i][0]=1;
        per(j,len-i+1,1)
        {
            if(s[i]==‘1‘)
                dp[i][j] = (dp[i+1][j-1]+C[len-i][j])%mod;
            else
                dp[i][j] = dp[i+1][j];
        }
    }
}
int main()
{
    scanf("%s%lld", s+1, &k);
    len = strlen(s+1);
    ll  tmp, cnt=0, ans=0;
    rep(i,1,len) if(s[i]==‘1‘) ++cnt;
    Init();
    rep(i,1,1000)
    {
        tmp = get(i);
        if(i==1) ans1[i] = 0;
        else  ans1[i] = ans1[tmp]+1;
        if(ans1[i]==k-1)
            ( ans += dp[1][i]%mod ) % mod;
    }
    if(k==0) ans = 1;
    if(k==1) ans = len-1;
    printf("%lld\n", (ans+mod)%mod);

    return 0;
}

D. Bash and a Tough Math Puzzle

题意: n 个数,两个操作:1、更改第 i 个数; 2、在区间 [l,r] 内,最多改变一个数,问是否能让 [l,r] 的gcd 等于 x 。

tags: 线段树单点更新,区间查询。如果区间内有超过 1 个数不是 x 的倍数,那就不能。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 500005;

int n, tree[N<<2], cnt;
void update(int ro, int L, int R, int x, int y)
{
    if(L==R && L==x) {
        tree[ro] = y;
        return ;
    }
    int mid = L+R>>1;
    if(x <= mid)
        update(ro<<1, L, mid, x, y);
    else
        update(ro<<1|1, mid+1, R, x, y);
    tree[ro] = __gcd(tree[ro<<1], tree[ro<<1|1]);
}
bool query(int ro, int L, int R, int l, int r, int x)
{
    if(cnt>1) return false;
    if(l<=L && R<=r)
    {
        if(tree[ro]%x==0) return true;
        if(L==R && tree[ro]%x!=0) { ++cnt; return false; }
    }
    int mid = L+R>>1;
    if(l<=mid) {
        query(ro<<1, L, mid, l, r, x);
    }
    if(mid<r) {
        query(ro<<1|1, mid+1, R, l, r, x);
    }
    if(cnt>1) return false;
    return true;
}
int main()
{
    scanf("%d", &n);
    int ai, ti, l, r, x, y, q;
    rep(i,1,n)
    {
        scanf("%d", &ai);
        update(1, 1, n, i, ai);
    }
    scanf("%d", &q);
    while(q--)
    {
        scanf("%d", &ti);
        if(ti==1) {
            scanf("%d%d%d", &l, &r, &x);
            cnt = 0;
            if(query(1, 1, n, l, r, x)) puts("YES");
            else puts("NO");
        }
        else {
            scanf("%d%d", &x, &y);
            update(1, 1, n, x, y);
        }
    }

    return 0;
}

原文地址:https://www.cnblogs.com/sbfhy/p/8336791.html

时间: 2024-11-02 21:54:11

Codecraft-18 and Codeforces Round #458 C dp D 线段树的相关文章

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

Codeforces Round #250 (Div. 1) D 线段树

看看type = 2的操作,对于区间[l,r]内的元素对x取模,由于取模肯定不能和取模,所以只能每个元素取模,看上去不是区间更新,但是仔细一看,若区间[l,r]内所有的元素都小于x,那么这一区间不需要管,所以还是存在区间整段操作,所以需要lazy,这里也算是一个剪枝了,剩下的就是type = 3的 单点更新,还有type = 1的区间求和,整体操作不难 int n,m; ll nnum[100000 + 55]; typedef struct Node { int l,r; ll sum; ll

Educational Codeforces Round 6 E dfs序+线段树

题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili上电子科技大学发的视频学习的 将一颗树通过dfs编号的方式 使每个点的子树的编号连在一起作为相连的区间 就可以配合线段树搞子树 因为以前好像听说过 线段树可以解决一种区间修改和查询区间中不同的xx个数...所以一下子就想到了... 但是我不会写线段树..只会最简单的单点修改区间查询...不会用延迟标

Codeforces Beta Round #12 D. Ball (线段树)

题目大意: n个女性中,如果有一个女性的三维比这个女性的三维都大,这个女性就要自杀.问要自杀多少个. 思路分析: 先按照第一维排序. 然后离散化第二维,用第二维的下标建树,树上的值是第三维,更新的时候取最大值. 注意是按照第一维度从大到小进入线段树. 而且还要严格递增. 所以处理第一维度比较大小的时候要分开处理,要把相同的先判断,再更新入树. 那么如何判断这个女性是否自杀. 首先,你知道第一维度是从大到小的,所以先进树了的节点的第一维度一定更大. 再次,我们考虑第二维度,我们去树上第二维度下标大

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

codeforces 444 C. DZY Loves Colors(线段树)

题目大意: 1 l r x操作 讲 [l,r]上的节点涂成x颜色,并且每个节点的值都加上 |y-x| y为涂之前的颜色 2 l r  操作,求出[l,r]上的和. 思路分析: 如果一个区间为相同的颜色.那么我们才可以合并操作. 所以我们之前找相同的区间就好. 但是问题是如何合并操作. 那么我们定义一个val  表示这个区间每个位置上应该加上的值. pushdown 的时候这个值是可以相加的. #include <cstdio> #include <iostream> #includ

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. f[n] 是斐波那契数列 也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少 通过简单的公式叠加也能求和 F[n]  = f[n - 1] * b + f[n - 2] * a F[n - 1] = f[n - 2] * b + f[n - 3] * a ..

Codeforces 444C DZY Loves Colors 水线段树

题目链接:点击打开链接 水.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set> #include <vector> #include <map> using namespace std; #define ll long long #defi

Educational Codeforces Round 26 D dp,思维

Educational Codeforces Round 26 D. Round Subset 题意:有 n 个数,从中选出 k 个数,要使这 k 个数的乘积末尾的 0 的数量最多. tags:dp好题 dp[i][j][l] 表示前 i 个数,选取了其中 j 个数,分解因子后有 l 个 5时,最多有多少个 2 .i 这一维明显可以省略. 这题一开始有个地方写挫了..选取 j 个数时,应该反着来,即 for( j, k, 1) ,不是 for( j, 1, k) ,不然会多算. #include