CF -- 674(div3):A~F题(题解)

A. Floor Number
题意:

Petya的公寓号是n,公寓楼号是这样安排的,第一层是1,2号,第二层是3到 (x + 2), 第三层是(x + 3)到(2x + 2)…依次类推。问Petya住第几层。

思路:

这里简单的谈一下快速向上取整的思路,x / y 快速向上取整,在不用库函数的情况下,ceil(x / y) = (x - 1) / y + 1

AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
    int n, x;
    scanf("%d%d", &n, &x);
    if (n <= 2) {
        puts("1");
        return;
    }
    int ans = (n - 2 - 1) / x + 1;
    printf("%d\n", ans + 1);
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}
B. Symmetric Matrix
题意

Masha有n种类型的2 * 2图块,每个类型有无限多个,问是否可以构成一个m * m的图块,这个图块关于主对角线对称。任意两个图块不能有覆盖。

思路

当m为奇数时,肯定不能构成。
当m为偶数时,关于主对角线对称,我们只需保证有一个块的[1][0]和[0][1]相同,就能构成。

AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 150;
int a[3][3];
void solve() {
    int n, m;
    bool f = false;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) {
        for (int i = 0; i < 2; ++i) {
            for (int j = 0; j < 2; ++j) {
                scanf("%d", &a[i][j]);
            }
        }
        if (a[1][0] == a[0][1]) {
            f = true;
        }
    }
    if ((m & 1) || !f) {
        puts("NO");
    } else {
        puts("YES");
    }
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}
C. Increase and Copy
题意

最开始数组里面有一个元素为1,即a = {1}
你每一步可以完成以下操作:
1.将数组中的任意一个元素复制到末尾。
2.将数组中的任意一个元素+1.
问将数组元素和变为n,最少需要多少步。

思路

思路:
很显然我们可以先将第一个加x,然后再复制y次,是得到最优(次数最少)的n。
令m = x + y;
n = (x + 1) * ( y + 1); —> 式子a
两个自变量x和y,一个因变量m。
由式子a减少自变量的数目,y = n / (x + 1) - 1 -->式子b;
然后我们只需要枚举一个变量x即可。
这里需要注意,除数,我们需要 ceil(X/Y) = (X - 1)/Y + 1 或者 ceil(X/Y) = (X + Y - 1) / Y
式子b变为 y = (n - 1) / (x + 1);

AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 200000 + 50;
const int mod = 1e9 + 7;
typedef long long ll;
void solve() {
   ll n;
   scanf("%lld", &n);
   if (n == 1) {
       puts("0");
       return;
   }
   ll i = 1, ans = 1e9;
   while (i * i <= n) {
        ans = min(ans, (n - 1) / (i + 1) + i);
        i++;
   }
    printf("%lld\n", ans);
}
int main() {
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i) {
        solve();
    }
    return 0;
}
D. Non-zero Segments
题意

数组里有n个整数,Kolya 不喜欢0, 所以不能连续的子序列和等于0,你可以插入一些无穷大进去,使得连续子序列和不等于0。问最少需要插入多少个无穷大?

思路

算数组中有多少个连续子序列和为0的个数,我们都能想到用map或者set来求,但是这个题存在满足子序列和为0的区间覆盖。例如 -2, -2 4, -2.
[1,3]和[2,4]都满足,但是只需要插入一个即可,在[2,3]之间插入一个无穷大即可,多枚举几个这样的重复区间,我们会得到一个规律,只要区间重复我们就可以在覆盖区间里面插入一个无穷大即可,那么还会有这样一种情况,-2, -2, 4, -2, -2,我们不考虑重复区间,[1,3]和[3,5]这两个区间满足,我们用set来处理这个,当查到当前位置有序列为0的,记录答案,删除原来的记录,插入当前的sum和前一个sum(处理一个区间的左端点和另一个区间的右端点覆盖,仔细品)。

AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200000 + 50;
void solve() {
   int n, x, ans = 0;
   scanf("%d", &n);
   ll sum = 0;
   set<ll> st;
   st.insert(sum);
   for (int i = 0; i < n; ++i) {
        scanf("%d", &x);
        sum += x;
        if (st.count(sum)) {
            ans++;
            st.clear();
        }
        st.insert(sum);
        st.insert(sum - x);
   }
   printf("%d\n", ans);
}
int main() {
    //int t;
    //scanf("%d", &t);
    //for (int i = 0; i < t; ++i) {
        solve();
    //}
    return 0;
}
 
E. Rock, Paper, Scissors
题意

Alice and Bob在玩石头剪刀布的游戏,Alice要出a1,a2,a3个石头,剪刀,布,Bob要出b1,b2,b3。a1+a2+a3 = b1 + b2 + b3 = n;
求Alice 能赢的最小回合数;Alice能赢的最大回合数。

思路

最大回合数很好求,让alice能赢的都赢(看代码),
最少回合数,Alice 的出石头的数目,先用Bob的布消去,如果没消去完,再用Bob的石头消去,这样Alice出石头赢得局数变得最小,出剪刀和布也是如此。最后再求Alice能赢多少局。

AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200000 + 50;
int n, a[4], b[4];
void go(int x, int y, int z) {
    if (a[x] < b[y]) {
        a[x] = 0;
        b[y] -= a[x];
   } else {
        a[x] -= b[y];
        if (a[x] > b[z]) {
            a[x] -= b[z];
            b[z] = 0;
        } else {
            a[x] = 0;
            b[z] -= a[x];
        }
   }
}
void solve() {
   scanf("%d", &n);
   for (int i = 1; i <= 3; ++i) scanf("%d", &a[i]);
   for (int i = 1; i <= 3; ++i) scanf("%d", &b[i]);
   int mx = min(a[1], b[2]) + min(a[2], b[3]) + min(a[3], b[1]);
   int mi = mx;
   go(1, 3, 1);
   go(2, 1, 2);
   go(3, 2, 3);
   mi = min(mi, min(a[1], b[2]) + min(a[2], b[3]) + min(a[3], b[1]));
   printf("%d %d\n", mi, mx);
}
int main() {
    //int t;
    //scanf("%d", &t);
    //for (int i = 0; i < t; ++i) {
        solve();
    //}
    return 0;
}
F. Number of Subsequences
题意

给出一个字符串,字符串包括’a’,‘b’,‘c’,’?‘这四个字符,’?'可代替abc中的任意一个,问这个字符串构成子序列为"abc"的总个数。

思路

动态规划问题,后面的状态是由前面的状态推出来的。
设 dp[i][0] 代表当前序列有多少个,dp[i][1],表示有多少个a,dp[i][2],表示有多少个ab,dp[i][3] 表示有多少个abc

AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200000 + 50;
const int mod = 1e9 + 7;
char s[maxn];
ll dp[maxn][4]; // dp[i][0] 代表有序列?,dp[i][1],表示有多少个a,dp[i][2],表示有多少个ab序列,dp[i][3] 表示有多少个abc序列
// ?对序列a有贡献,a对序列ab有贡献,ab对序列abc有贡献。贡献是累计的。
void solve() {
   int n;
   scanf("%d%s", &n, &s);
   dp[0][0] = 1;
   for (int i = 0; i < n; ++i) {
        //当前状态由上一个状态推过来
        for (int j = 0; j <= 3; ++j) {
            dp[i + 1][j] = dp[i][j];
        }
        if (s[i] == 'a') {
            dp[i + 1][1] = dp[i + 1][1] + dp[i][0] % mod;
        } else if (s[i] == 'b') {
            dp[i + 1][2] = dp[i + 1][2] + dp[i][1] % mod;
        } else if (s[i] == 'c') {
            dp[i + 1][3] = dp[i + 1][3] + dp[i][2] % mod;
        } else {
            dp[i + 1][0] = dp[i][0] * 3 % mod;
            for (int j = 1; j <= 3; ++j) {
                dp[i + 1][j] = (dp[i][j] * 3 % mod + dp[i][j - 1] % mod) % mod;
            }
        }
   }
   printf("%lld\n", dp[n][3] % mod);
}
int main() {
    //int t;
    //scanf("%d", &t);
    //for (int i = 0; i < t; ++i) {
        solve();
    //}
    return 0;
}
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空皓月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值