The 10th Shandong Provincial Collegiate Programming Contest 2019山东省赛游记+解题报告

 

比赛结束了几天...这篇博客其实比完就想写了...但是想等补完可做题顺便po上题解...

5.10晚的动车到了济南,没带外套有点凉。酒店还不错。

5.11早上去报道,济南大学好大啊...感觉走了一个世纪才到了他们的教学楼...跟我们学校比起来...

中午吃的他们的八食堂,对于我来说并没有吃饱,食堂看着很好但是给队员的窗口只有一个。其他的都没办法吃。

下午热身赛AB水题。C题刚开始觉得是二分,中途发现二分是错的然后改了几发过了之后就走了。出来之后才看的D,才知道为啥要放弃D了233

晚上吃饭吃得有点晚赶不回去打Atcoder。回到酒店后躺了会床。洗完澡11点多了就把Atcoder的ABCD切了,12点多就上床睡了(主要是E题不会写。待会去补。

第二天比赛,拿到题册后想着要抢一发一血,先开的A题,一紧张写WA了。改了一下才过的。之后看了下D发现跟图无关,可以直接写就一发过了。

然后我就贡献了3发H的罚时啦。然后就没啦。全靠队友带躺走进金牌区。封榜后看出E的ans怎么统计但是就是不知道用啥数据结构维护。算是比较遗憾的啦。

其实我很不想被人带躺。进了金牌区我并不觉得很开心甚至觉得很丢脸。因为我对队伍的贡献就只有傻逼的罚时和一两道签到题。还是得变强啊。

 

A - Calandar

定位:签到

题意:重新定义了一年有12个月,1个月有30天,一周只有5天。给出一个年月日加上它的星期数,求另外一个年月日是星期几。

思路:求出两个日期之间的天数差,然后把星期几给加上这个差再mod 5就好了。注意负数的情况。比赛的时候想复杂了。还分类讨论了。。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const char s[5][20] = {
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
char str[20];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        ll a, b, c, d, e, f;
        scanf("%lld%lld%lld", &a, &b, &c);
        scanf("%s", str);
        scanf("%lld%lld%lld", &d, &e, &f);
        ll sum1 = a * 30 * 12 + b * 30 + c;
        ll sum2 = d * 30 * 12 + e * 30 + f;
        ll temp = sum2 - sum1;
        ll id = 0;
        for (int i = 0; i < 5; i++) {
            if (strcmp(str, s[i]) == 0) {
                id = i;
                break;
            }
        } 
        id += temp;
        id %= 5;
        while (id < 0) id += 5;
        puts(s[id]);
    }   
    return 0;
}
View Code

 

B - Flipping Game

定位:DP,组合数学,难

比赛的时候完全不懂。

题意:两个长度为n的01串分别为初态和末态,要求操作K轮,每轮操作m次,每次是把0变成1或者1变成0,要求从初态到末态有多少种方案。

思路:问题可以进一步简化,只要看初末有多少个字符不同,设为x。

$dp\left[ p\right] \left[ i\right]$表示在第$p$轮里有$i$个字符不同要变成相同的方案数

转移方程就是下面这样

$dp\left[ p\right] \left[ i\right] =\sum ^{\min \left( i,m\right) }_{j}C_{i}^{j} C_{n-i}^{m-j}dp\left[ p-1\right] \left[ i-j+m-j\right]$

初始:$dp\left[ 0\right] \left[ 0\right] = 0$ 第0轮0个需要变的方案肯定为1嘛。

对转移方程的解释是,在$i$个不同的里面挑了$j$来变成相同的,那么现在就还有$i-j$个是不同的,而在$n-i$个相同的里面挑了$m-j$个来变成不同的 所以这一轮之前需要变$i-j+m-j$个。

组合数就是由于顺序的不同导致方案数变多。其实还有一个$m-j$小于等于$n-i$的限制,但是由于组合数我只求到了相等的时候 所以比它大的时候组合数为0,答案不会受到影响。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 200;
const ll MOD = 998244353;
ll C[N][N], dp[N][N];

void init() {
    C[0][0] = 1;
    C[1][0] = C[1][1] = 1;
    for (int i = 2; i < N; i++) {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++) 
            C[i][j] = C[i-1][j] + C[i-1][j-1], C[i][j] %= MOD;
    }
}

char num[2][N];

int main() {
    init();
    int T;
    scanf("%d\n", &T);
    while (T--) {
        memset(dp, 0, sizeof(dp));
        int n, m, k;
        scanf("%d%d%d", &n, &k, &m);
        int x = 0;
        scanf("%s", num[0]);
        scanf("%s", num[1]);
        for (int i = 0; i < n; i++) x += num[0][i] != num[1][i];
        dp[0][0] = 1;
        for (int p = 1; p <= k; p++) {
            for (int i = 0; i <= n; i++) {
                for (int j = 0; j <= i && j <= m; j++) {
                    dp[p][i] += dp[p - 1][i - j + m - j] * C[i][j] % MOD * C[n - i][m - j] % MOD;
                    dp[p][i] %=
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值