第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(沈阳)

第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(沈阳)

D . J o u r n e y t o U n ′ G o r o D. Journey to Un'Goro D.JourneytoUnGoro

题 意 题意

构 造 长 度 为 n 的 字 符 串 , 每 个 点 是 b 或 r 。 之 后 选 两 个 点 L , R ( 1 ≤ L ≤ R ≤ n ) , 使 得 [ L , R ] 中 有 奇 数 个 r , 问 ( L , R ) 点 对 的 最 大 数 量 。 按 字 典 序 输 出 构 造 的 序 列 , 如 构造长度为n的字符串,每个点是b或r。之后选两个点L,R(1 \leq L\leq R\leq n),使得[L,R]中有奇数个r,问(L,R)点对的最大数量。按字典序输出构造的序列,如 nbrL,R(1LRn),使[L,R]r(L,R) 果 数 量 > 100 只 输 出 前 100 个 果数量>100只输出前100个 >100100

解 法 解法

把 b 看 成 0 , r 看 成 1 , 的 到 01 数 组 b , 对 b 求 异 或 前 缀 和 。 把b看成0,r看成1,的到01数组b,对b求异或前缀和。 b0r101bb

( L , R ) 中 有 奇 数 个 1 ⇒ b [ r ] − b [ l − 1 ] 是 奇 数 ⇒ b [ r ] 与 b [ l − 1 ] 奇 偶 性 不 同 (L,R)中有奇数个1 \Rightarrow b[r] - b[l - 1]是奇数 \Rightarrow b[r]与b[l - 1]奇偶性不同 (L,R)1b[r]b[l1]b[r]b[l1]

设 b [ 0 ∽ n ] 中 有 x 个 0 , y 个 1 , ( L , R ) 的 选 法 有 x ∗ y 种 , 当 x ∗ y = ⌊ ( n + 1 ) 2 ⌋ ⌈ ( n + 1 ) 2 ⌉ 时 最 大 。 设b[0\backsim n]中有x个0,y个1,(L,R)的选法有x*y种,当x*y= \lfloor \frac {(n+1)} {2} \rfloor \lceil \frac {(n+1)} {2} \rceil时最大。 b[0n]x0,y1(L,R)xy,xy=2(n+1)2(n+1)

可 以 看 出 b 数 组 中 , 0 和 1 的 个 数 都 不 能 超 过 ⌈ ( n + 1 ) 2 ⌉ , 根 据 这 个 条 件 进 行 剪 枝 。 可以看出b数组中,0和1的个数都不能超过 \lceil \frac {(n+1)} {2} \rceil,根据这个条件进行剪枝。 b012(n+1),

因 为 只 要 输 出 100 组 , 可 能 能 用 d f s 过 , 事 实 证 明 也 是 可 以 的 。 因为只要输出100组,可能能用dfs过,事实证明也是可以的。 100dfs

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 100010;

char s[N];
int n, m, lim, cnt;

void dfs(int u, int cnt0, int cnt1, int sum) {
    if (cnt0 > lim || cnt1 > lim)   return ;
    if (u == n + 1) {
        s[n + 1] = '\0';
        cout << s + 1 << endl;
        cnt ++;
        if (cnt >= 100) exit(0);
    }
    s[u] = 'b';
    int t0 = 0, t1 = 0;
    if (sum & 1)  t1 = 1;
    else t0 = 1;
    dfs(u + 1, cnt0 + t0, cnt1 + t1, sum);
    s[u] = 'r';
    dfs(u + 1, cnt0 + (t0 ^ 1), cnt1 + (t1 ^ 1), sum ^ 1);
}

int main() {
    cin >> n;
    cout << 1ll * (n + 1 >> 1) * (n + 2 >> 1) << endl;
    lim = (n + 2 >> 1);
    dfs(1, 1, 0, 0);
    return 0;
}

F . K o b o l d s a n d C a t a c o m b s F.Kobolds and Catacombs F.KoboldsandCatacombs

题 意 题意

给 一 个 数 组 a , 将 a 分 成 尽 可 能 多 的 段 , 使 得 只 对 段 内 排 序 , 能 够 使 a 变 成 升 序 给一个数组a,将a分成尽可能多的段,使得只对段内排序,能够使a变成升序 aa使使a

解 法 解法

设 b 为 a 稳 定 排 序 后 的 数 组 , 则 每 一 段 内 a 和 b 中 的 元 素 在 原 数 组 中 的 下 标 构 成 的 集 合 一 设b为a稳定排序后的数组,则每一段内a和b中的元素在原数组中的下标构成的集合一 baab
定 相 同 定相同

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1000010;
struct Node {
    int x, i;
    bool operator < (const Node no) const {
        return x < no.x;
    }
}node[N];
int n, m;
int s[N], cnt;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf("%d", &node[i].x);
        node[i].i = i;
    }
    int ans = 0;
    stable_sort(node + 1, node + 1 + n);
    for (int i = 1; i <= n; i ++) {
        int j = i;
        bool flag = 1;
        do {
            if (flag) cnt = 0, flag = 0;
            s[j] ^= 1;
            if (s[j]) cnt ++;
            else cnt --;

            int t = node[j].i;
            s[t] ^= 1;
            if (s[t]) cnt ++;
            else cnt --;
            j ++;
        }while (cnt);
        i = j - 1;
        ans ++;
    }
    printf("%d", ans);
    return 0;
}

G . T h e W i t c h w o o d G.The Witchwood G.TheWitchwood

解 法 解法

降 序 排 序 后 对 前 m 个 数 求 和 降序排序后对前m个数求和 m

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 10010;
LL a[N], n, m;

int main() {
    cin >> n >>m;
    for (int i = 1; i <= n; i ++)   cin>> a[i];
    sort(a + 1, a + 1 + n, greater<int>());
    LL ans = 0;
    for (int i = 1; i <= m; i ++)   ans += a[i];
    cout << ans;
    return 0;
}

H . T h e B o o m s d a y P r o j e c t H.The Boomsday Project H.TheBoomsdayProject

题 意 题意

给 定 租 一 次 车 的 价 格 r , 以 及 某 个 人 哪 一 天 要 租 车 , 那 一 天 要 租 多 少 次 车 。 有 一 些 折 扣 给定租一次车的价格r,以及某个人哪一天要租车,那一天要租多少次车。有一些折扣 r 卡 , 给 定 每 张 折 扣 卡 的 有 效 天 数 , 免 费 租 车 次 数 , 售 价 。 问 这 个 人 的 最 小 花 费 。 卡,给定每张折扣卡的有效天数,免费租车次数,售价。问这个人的最小花费。

解 法 解法

租 车 的 总 次 数 只 有 5 e 5 , 日 期 的 编 号 有 1 e 9 , 考 虑 按 车 分 类 而 不 是 按 哪 一 天 分 类 。 租车的总次数只有5e5,日期的编号有1e9,考虑按车分类而不是按哪一天分类。 5e51e9
将 单 车 拿 出 来 后 对 它 们 按 照 所 在 日 期 编 号 排 序 。 定 义 f [ i ] 为 租 前 i 辆 车 的 最 小 花 费 。 将单车拿出来后对它们按照所在日期编号排序。定义f[i]为租前i辆车的最小花费。 f[i]i

第 i 辆 车 不 适 用 折 扣 卡 : f [ i ] = f [ i − 1 ] + r 第i辆车不适用折扣卡:f[i] = f[i - 1] + r if[i]=f[i1]+r
使 用 折 扣 卡 有 如 下 转 移 方 程 如 下 , 如 果 不 优 化 会 超 时 使用折扣卡有如下转移方程如下,如果不优化会超时 使

	for (int i = 1; i <= n; i ++)	//枚举单车
		for (int j = 1; j <= m; j ++)	//枚举m张折扣卡
			forint k...//租第k辆单车时买j号折扣卡(要保证能覆盖i)
				f[i] = min(f[i], f[k-1]+c[j]);	//第k辆车被折扣卡抵扣,因此从f[k-1]转移

f 数 组 是 升 序 的 , 使 用 折 扣 卡 的 转 移 就 要 尽 可 能 地 从 前 面 的 状 态 转 移 , 又 因 为 折 扣 卡 有 f数组是升序的,使用折扣卡的转移就要尽可能地从前面的状态转移,又因为折扣卡有 f使 次 数 和 天 数 限 制 , 转 移 点 只 能 在 靠 近 i 的 某 个 范 围 内 取 。 即 在 靠 近 i 的 合 法 范 围 内 取 最 靠 次数和天数限制,转移点只能在靠近i的某个范围内取。即在靠近i的合法范围内取最靠 ,ii 前 的 。 对 每 种 折 扣 卡 都 用 一 个 变 量 i d 存 最 优 转 移 点 的 下 标 就 能 优 化 掉 对 k 的 枚 举 。 前的。对每种折扣卡都用一个变量id存最优转移点的下标就能优化掉对k的枚举。 idk

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 300010;

int day[N], id[N], d[N], cnt[N], c[N], n, m, r;
LL f[N];

int main() {
    cin >> m >> n >> r;
    int T = n;
    n = 0;
    for (int i = 1; i <= m; i ++) {
        cin >> d[i] >> cnt[i] >> c[i];
        id[i] = 1;
    }
    while (T --) {
        int a, b;
        cin >> a >> b;
        for (int i = 1; i <= b; i ++)   day[++ n] = a;
    }
    sort(day + 1, day + 1 + n);

    for (int i = 1; i <= n; i ++) {
        f[i] = f[i - 1] + r;
        for (int j = 1; j <= m; j ++) {
            while (day[i] - day[id[j]] + 1 > d[j] || i - id[j] + 1 > cnt[j])    id[j] ++;
            f[i] = min(f[i], f[id[j] - 1] + c[j]);
        }
    }
    cout << f[n] <<endl;
    return 0;
}

I . R i s e o f S h a d o w s I.Rise of Shadows I.RiseofShadows

题 意 题意

一 天 有 H 小 时 , 一 小 时 有 M 分 钟 , 问 有 多 少 个 整 数 分 钟 满 足 时 针 和 分 针 的 夹 角 ≤ α 一天有H小时,一小时有M分钟,问有多少个整数分钟满足时针和分针的夹角 \leq \alpha HMα

α = 2 π A H M \alpha= \frac{2\pi A}{HM} α=HM2πA

解 法 解法

把 表 盘 的 一 圈 分 为 H × M 格 。 把表盘的一圈分为H\times M格。 H×M

每 分 钟 , 分 针 走 2 π M 弧 度 , 也 就 是 M 格 , 时 针 走 2 π H M 弧 度 , 也 就 是 1 格 。 可 以 得 到 如 下 的 式 子 。 每分钟,分针走\frac{2\pi}{M}弧度,也就是M格,时针走\frac{2\pi}{HM}弧度,也就是1格。可以得到如下的式子。 M2πMHM2π1

( 2 π M − 2 π M H ) t ≤ 2 π A M H ( m o d M H ) (\frac{2\pi}{M}-\frac{2\pi}{MH})t\leq \frac{2\pi A}{MH}(mod MH) (M2πMH2π)tMH2πA(modMH)

⇒ ( H − 1 ) t ≤ A ( m o d M H ) \Rightarrow (H-1)t\leq A(modMH) (H1)tA(modMH)

令 d = g c d ( H − 1 , M H ) 令d=gcd(H-1,MH) d=gcd(H1,MH)

我 们 要 求 的 就 是 % M H 意 义 下 的 t 的 个 数 我们要求的就是\%MH意义下的t的个数 %MHt

令 0 < K ≤ A , 且 K ∣ d 令0<K\leq A,且K|d 0<KA,Kd

对 每 个 这 样 的 K , 在 % M H 的 意 义 下 , t 的 解 的 个 数 为 g c d ( H − 1 , M H ) 对每个这样的K,在\%MH的意义下,t的解的个数为gcd(H-1, MH) K,%MHtgcd(H1,MH) 似乎是个定理

算 上 负 数 和 0 , 这 样 的 K 一 共 有 A d × 2 + 1 个 , 对 每 个 K , 解 的 个 数 为 d , 所 以 原 不 等 式 的 解 的 个 数 为 : 算上负数和0,这样的K一共有\frac{A}{d} \times2+1个,对每个K,解的个数为d,所以原不等式的解的个数为: 0KdA×2+1,Kd:

d × ( A d × 2 + 1 ) d\times(\frac{A}{d}\times2+1) d×(dA×2+1)

当 A = H M 2 时 , α = π , 正 好 是 半 圈 , 一 个 指 针 顺 时 针 与 逆 时 针 绕 半 圈 的 位 置 会 被 重 复 计 算 , 这 个 时 候 当A=\frac{HM}{2}时,\alpha=\pi,正好是半圈,一个指针顺时针与逆时针绕半圈的位置会被重复计算,这个时候 A=2HMα=π, 要 特 判 。 一 天 里 的 每 一 分 钟 都 是 合 法 情 况 一 共 有 H × M 种 要特判。一天里的每一分钟都是合法情况一共有H\times M种 H×M

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;


int main() {
    LL h, m, a;
    cin >> h >> m >> a;
    LL d = __gcd(h - 1, m * h);
    if (a * 2 == h * m)    cout << h * m;
    else    cout << d * (a / d * 2 + 1);
    return 0;
}

J . D e s c e n t o f D r a g o n s J.Descent of Dragons J.DescentofDragons

看 起 来 像 主 席 树 。 但 是 不 会 。 没 找 到 题 解 , 哪 位 大 佬 有 题 解 麻 烦 给 个 链 接 顺 便 踢 我 一 下 看起来像主席树。但是不会。没找到题解,哪位大佬有题解麻烦给个链接顺便踢我一下 便

K . S c h o l o m a n c e A c a d e m y K.Scholomance Academy K.ScholomanceAcademy

解 法 解法

把 F P R 看 成 横 坐 标 x , T P R 看 成 纵 坐 标 y 。 θ 从 大 小 变 化 的 过 程 中 , x 和 y 都 是 递 增 的 , 把FPR看成横坐标x,TPR看成纵坐标y。\theta从大小变化的过程中,x和y都是递增的, FPRxTPRyθxy 即 给 定 的 函 数 是 一 个 单 调 递 增 函 数 , 且 经 过 ( 0 , 0 ) 和 ( 1 , 1 ) 两 个 点 。 函 数 构 成 了 一 些 矩 形 即给定的函数是一个单调递增函数,且经过(0,0)和(1,1)两个点。函数构成了一些矩形 (0,0)(1,1) 。 我 们 要 求 的 就 是 矩 形 的 面 积 和 。 θ 枚 举 关 键 的 值 就 行 , 也 就 是 题 目 中 输 入 的 数 。 从 大 。我们要求的就是矩形的面积和。\theta枚举关键的值就行,也就是题目中输入的数。从大 θ 到 小 枚 举 θ , 累 加 y × Δ x 即 可 求 得 答 案 。 到小枚举\theta,累加y\times \Delta x 即可求得答案。 θy×Δx
一 个 细 节 : 两 个 数 相 同 时 , + 的 排 在 前 面 一个细节:两个数相同时,+的排在前面 +

#include <bits/stdc++.h>

#define x first
#define y second

using namespace std;

typedef long long LL;


const int N = 1000010;

struct Node {
    char c;
    int x;
    bool operator< (const Node &u)  const {
        if (x == u.x)   return c < u.c;    
        return x < u.x;
    }
}node[N];
int n, m, cnt;
double tp, fp, fn, tn;

double tpr() {
    return tp / (tp + fn);
}

double fpr() {
    return fp / (tn + fp);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        char s[2];
        int x;
        scanf("%s%d", s, &x);
        node[i] = {s[0], x};
        if (s[0] == '+')    fn ++;
        else tn ++;
    }
    double pre = 0, ans = 0;
    sort(node + 1, node + 1 + n);
    for (int i = n; i >= 1; i --) {
        if (node[i].c == '+')   fn --, tp ++;
        else tn --, fp ++;
        ans += tpr() * (fpr() - pre);
        pre = fpr();
    }
    printf("%.10f", ans);
    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值