cf思维题

1、B. Paranoid String

题意:操作一:01可以变成1,操作二:10可以变成0。给定一个串,判断字串经过若干次操作,能否长度变成1,统计数量。

思路:对01来说,1可以吃掉0,然后前边不是0的,又可以通过10变成0。所以,能否变成一,取决于最后两个字符是否相同。

2、C. Zero Path

题意:给定只包含-1,1的一个矩阵,问从矩阵左上角走到矩阵右下角,只能左走一步和右走一步,是否存在路径使得和为0。

思路: 利用dp求出来从左上到右下的最大和和最小和。观察发现,如果从同一点向下走一步和向右走一步,到达斜斜下方,那么结果相差可能为-2,0,2.所以矩阵能实现的结果的可能值是在min~max之间,和它俩奇偶性相同的数。

拓展:思考如何打印出来路径

3、C. Helping the Nature

题意:给定三种操作,op1:将[1,i]位置对应的数字都减1,op2:将[i,n]位置对应的数字都减1,op3:将所有的数字都加1。问最少需要多少步,能把给定序列变成一个全零序列。

思路:利用差分进行求解,举个具体例子然后结合代码进行分析。

    cin >> n;
    int ans = 0;
    int cur;//代表第一位的终值
    for(int i = 1; i <= n; i++){
        cin >> x;
        if(i == 1) {
            pre = x;
            cur = x;continue;
        }
        else if(pre - x > 0){
            cur -= pre - x;//更新第一位的值
        }
        ans += abs(pre - x);//abs(pre - x), 求后边/qi 前边减多少
        pre = x;
    }
    cout << ans + abs(cur) << endl;

4、D. Fake Plastic Trees

(一道很好的树上bfs)

题意:给一棵树,每个结点有一个合法区间范围,操作是,每次在树上选一条链和一个c,然后链上每个点都加上c。初始树上每个点的值都是零,求最少多少次操作能让每个点的区间范围都合法。

思路:树上bfs。每次根据叶子节点来推父亲节点。

const int N = 2e5 + 10;
int t, n, d[N];
int fa[N]; //记录父亲结点
int add[N]; //记录子节点的贡献和
int dn[N], up[N];
int ans;

int min(int a, int b){
    if(a < b) return a;
    return b;
}

void bfs(){
    queue<int> q;
    for(int i = 1; i <= n; i++){
        if(d[i] == 0) q.push(i);
    }
    while(!q.empty()){
        int u = q.front();
        q.pop();
        int f = fa[u];
        int dnn = dn[u], upp = up[u];
        if(add[u] < dnn) add[f] += upp, ans ++;
        else add[f] += min(add[t], upp);
        d[f] --;
        if(!d[f]) q.push(f); 
    }
}

void solve(){
    cin >> t;
    while(t -- ){
        cin >> n;
        ans = 0;
        memset(add, 0, sizeof add);
        memset(d, 0, sizeof d);
        fa[1] = 1;
        for(int i = 2; i <= n; i++){
            cin >> fa[i];
            d[fa[i]] ++;
        }
        for(int i = 1; i <= n; i++) cin >> dn[i] >> up[i];
        bfs();
        cout << ans << endl;
    }
}

5、C. awoo's Favorite Problem

题意:有两种操作,一种是把ab变成ba,一种是把bc变成cb。给定两个序列,判断能否经过若干次操作,把序列a变成序列b。

思路:set存储元素位置。记得交换!

string solve(){
    for(int i = 0; i < lena; i ++) {
        s[a[i] -'a'].insert(i);
    }
    for(int i = 0; i < lena; i++){
        if(a[i] == b[i]) {
            s[a[i] -'a'].erase(i);
            continue;
        }
        if(a[i] == 'a' && b[i] == 'b'){
            if(!s[1].size()) return "NO";
            int posb = *s[1].begin();
            int posc = *s[2].begin();
            if(s[2].size() && posc < posb) return "NO";
            s[0].erase(i);
            s[1].erase(posb);
            s[0].insert(posb);
            swap(a[i], a[posb]);
            continue;
        }
        if(a[i] == 'b' && b[i] == 'c'){
            ...
        }
        return "NO";
    }
    return "YES";
}

6、D. Guess The String

题意:交互题。有一个长度为n的字符串。给定两种询问方式,第一种是查询某个位置的字母是什么(最多26次),第二种是查询区间的不同字母的个数(最多6000次)。求字符串是啥。

思路:二分+思维。存下来每个元素最后出现的位置,从前往后遍历,查询(mid,i)和(mid,i - 1)中有多少个不同的字母,如果相同,就更新该字符出现的最后位置为i,否则就查询该位置的字符是啥,然后更新该字符最后出现的位置为i。

注意:第一,题目不是多组输入,这个点错了好多遍。第二,下标从1开始!第三,加上cout.flush之后速度会快一点,建议添加。

7、Map

利用向量关系去构造。

思路:
image

posted @ 2022-09-06 19:37  风归去  阅读(163)  评论(0编辑  收藏  举报