第 45 届国际大学生程序设计竞赛(ICPC)亚洲网上区域赛模拟赛 题解(除了C、G之后补)

整理的算法模板合集: ACM模板


这次比赛好多原题呀…(就是那种稍微拓展了一点的原题)

A、Easy Equation

在这里插入图片描述
题目大意:求 x + y + z = k x+y+z=k x+y+z=k的方案数,输入为四个数可取的范围。


前缀和差分。

首先一看数据范围是1e6就不可能 O ( n 2 ) O(n^2) O(n2)做,只能 O ( n ) O(n) O(n)

之前做过一道简化版的题,是求 x + y = z x+y=z x+y=z的方案数,用的好像是什么前缀和映射思想,我忘了,是CF上面的一次比赛题,但是我找不到了…这里是三个,所以把那个方法拓展一下即可。

实际上用前缀和来解决思路特别简单,大致是一个前缀和+递推DP的思想。

因为有三个数相加的方案数

我们用 f[i] 表示i能够被多少个前两个范围的数(x+y)加起来的方案数,我们直接循环x,那么所有从 xx+b的数都能被这个数递推过去,方案数+1,我们可以直接用前缀和来维护一个区间+1的操作,这样求得 f 数组,然后我们用同样的思路求g数组,其中g[i]表示的是i能够被多少个x+y+z的方案数,同样的我们维护一个前缀和差分,再求一次前缀和就是所有能通过x+y+z得到这个数的方案数,我们直接枚举所有d的范围,求和既是答案。

一个小插曲

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;

const int N = 1e8 + 7, M = 5000007, INF = 0x3f3f3f3f;

long long a, b, c, d;
long long f[N];
long long g[N];

int main()
{
   

    scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
    for(int i = 0; i <= a; ++ i){
   
        f[i] ++ ;
        f[i + b + 1] -- ;
    }
    for(int i = 1; i <= a + b; ++ i)
        f[i] += f[i - 1];
    for(int i = 0; i <= a + b; ++ i){
   
        g[i] += f[i];
        g[i + c + 1] -= f[i] ;
    }
    for(int i = 1 ;i <= a + b + c; ++ i)
        g[i] += g[i - 1];
    long long ans = 0;
    for(int i = 0; i <= d; ++ i)
        ans += g[i];
    printf("%lld\n", ans);
    return 0;
}

B、XTL’s Chessboard

在这里插入图片描述
在这里插入图片描述
题目大意:弹弹弹


SB题,直接输出2就行了,因为所有的点沿着45度角射出反弹最后都会回到起点,x-1和y-1互质的时候一定会经过角,就会直接反弹原路返回。所以只有起点和终点经过奇数次,答案就是2。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;

const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;

int n, m, t;
int a[N], b[N];
bool vis[N];
int ans;

int main()
{
   
    int x, y;
    while(scanf("%d%d%d%d", &n, &m, &x, &y) != EOF && n + m){
   
        printf("2\n");
    }
    return 0;
}

D、Pokemon Ultra Sun

在这里插入图片描述
题目大意:宝可梦们大战,你和对手都有一个血量,每一轮都是你打对手,攻击力为w,每次有p的概率对手掉血,1-p的概率你自己掉血,求比赛轮数的期望。


概率DP板子题…

我们用 f[i][j] 表示我方掉i血敌方掉j血的期望。
然后直接输出即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;

const int N = 3507, M = 5000007, INF = 0x3f3f3f3f;

int n, m, t;
int hp1, hp2, w;
double f[N][N];
double p;

int main()
{
   
    scanf("%d", &t);
    while(t -- ){
   
        scanf("%d%d%d%lf", &hp1, &hp2, &<
  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

繁凡さん

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

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

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

打赏作者

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

抵扣说明:

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

余额充值