暑假N天乐【比赛篇】 —— 2019杭电暑期多校训练营(第五场)

开启疯狂水题解模式,大概会持续好几次...直到我赶上进度为止。

以下题解包括:

\[1001【HDU-6624】 \\ 1004【HDU-6627】 \\ 1005【HDU-6628】 \\ 1006【HDU-6629】 \\ 1007【HDU-6630】\]

【1001】 数学 HDU-6624 fraction

http://acm.hdu.edu.cn/showproblem.php?pid=6624

找到最小正整数的 \(b\) 满足 \(a<b\) 且 \(a = bx(mod \ p)\)。

参考:https://blog.csdn.net/Sarah_Wang0220/article/details/98771865

可知:\(0<a<b\),\(bx=py+a\) ==> \(0<a=bx-py<b\) ==> \(\frac{p}{x} < \frac{b}{y} < \frac{p}{x-1}\),要求最小的 \(b\)。

迭代法:
\[
\begin{aligned}
& \because \frac{p}{x} < \frac{b}{y} < \frac{p}{x-1} \ 且 \ p > x \& \therefore \frac{p}{x} > 0 \ \ 取 \ t = \frac{p}{x} \& \therefore \frac{p-tx}{x} < \frac{b-ty}{y} < \frac{p-t(x-1)}{x-1} \& 取倒数得:\frac{x-1}{p-t(x-1)} < \frac{y}{b-ty} < \frac{x}{p-tx} \& 同理,继续减去左边的整数部分 \& 此时 \ b' = b - ty 不断减小
\end{aligned}
\]

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

void solve(ll a, ll b, ll &c, ll &d, ll e, ll f) {
    ll t = a/b;
    if(e/f > t) {
        c = t+1;
        d = 1;
        return ;
    }
    a = a - t*b;
    e = e - t*f;
    solve(f, e, d, c, b, a);
    c = c + t*d;
}

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        ll p, x;
        scanf("%lld%lld", &p, &x);
        ll b, y;
        solve(p, x, b, y, p, x-1);
        printf("%lld/%lld\n", b*x-p*y, b);
    }
    return 0;
}

【1004】 数学 HDU-6627 equation

http://acm.hdu.edu.cn/showproblem.php?pid=6627

给定 \(n\) 和 \(c\),输入 \(n\) 个 \(a_i\) 和 \(b_i\),计算所有 \(x\) 的解使得:\(\sum^{n}_{i=1} |a_ix+b_i| = c\)。

对于每个绝对值等式找出 \(x\) 的区间,再进行排序枚举区间,统计解的个数。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 1e5+5;

int n;
ll c;
ll suma[maxn], sumb[maxn];     // 记录 系数/常数 前缀和
map<double, int> vis;

struct node {
    ll a, b;
    double f;
    bool operator < (const node &q) const {
        return f > q.f;
    }
}p[maxn], ans[maxn];

bool cmp(node x, node y) {
    return x.f < y.f;
}

int main() {
    int t;
    scanf("%d", &t);
    suma[0] = sumb[0] = 0;
    while(t--) {
        vis.clear();
        scanf("%d%lld", &n, &c);
        for(int i = 1; i <= n; i++) {
            scanf("%lld%lld", &p[i].a, &p[i].b);
            p[i].f = -1.0*p[i].b/p[i].a;    // 每组方程等于 0的解
        }
        sort(p+1, p+1+n);
        for(int i = 1; i <= n; i++) {
            suma[i] = suma[i-1] + p[i].a;
            sumb[i] = sumb[i-1] + p[i].b;
        }
        int flag = 0;
        int cnt = 0;
        for(int i = 0; i <= n; i++) {
            ll A = suma[n] - 2*suma[i];     // 当前区间解的 系数 前缀和(分母)
            ll B = sumb[n] - 2*sumb[i];     // 当前区间解的 常数 前缀和
            ll C = c - B;        // 等式常数移到右边获取最终常数(分子)
            if(A == 0) {
                if(C == 0) {    // 无穷解
                    flag = 1;
                    break;
                }
                else {          // 无解
                    continue;
                }
            }
            else {
                ll temp = __gcd(abs(C), abs(A));
                double mark = 1.0 * C / A;
                if(vis[mark] == 0) {    // 去重
                    if((i==n || mark>p[i+1].f) && (i==0 || mark<=p[i].f)) {     // 边界判定
                        ans[cnt].a = C / temp;
                        ans[cnt].b = A / temp;
                        ans[cnt++].f = mark;
                    }
                }
            }
        }
        if(flag == 1) {
            printf("-1\n");
        }
        else {
            printf("%d", cnt);
            sort(ans, ans+cnt, cmp);
            for(int i = 0; i < cnt; i++) {
                if(ans[i].a*ans[i].b > 0) {
                    printf(" %lld/%lld", abs(ans[i].a), abs(ans[i].b));
                }
                else if(ans[i].a*ans[i].b == 0) {
                    printf(" 0/1");
                }
                else {
                    printf(" -%lld/%lld", abs(ans[i].a), abs(ans[i].b));
                }
            }
            printf("\n");
        }
    }
    return 0;
}

【1005】 思维 HDU-6628 permutation 1

http://acm.hdu.edu.cn/showproblem.php?pid=6628

\(t\) 组案例,已知序列为:\(p_1p_2...p_n\),定义差异序列为:\(p_2-p_1,p_3-p_2,...,p_n-p_{n-1}\)。给定 \(n\) 和 \(k\),求序列 \(1,2,3,...,n\) 中差异序列排名第 K 小的那个,输出它。(\(2 \leq n \leq 20 \ \ \ 1 \leq k \leq min(10^4,n!)\))

对于 \(n \leq 8\) 时,直接暴力就行。

对于 \(n > 8\) 时,找到规律:先放下 \(n\) 这个数,后面最小就是 \(1,2,3,...,n-1\),然后只需要对后 8 位进行排列即可,因为 \(8! > 10^4\)。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 4e4+500;

int a[10] = {1, 2, 3, 4, 5, 6, 7, 8};
int a_8[10] = {1, 2, 3, 4, 5, 6, 7};
int _a_8[10] = {1, 2, 3, 4, 5, 6, 8};
int tot, tot1, tot2, cnt;

struct node {
    int z[10];
    bool operator < (const node x) const {
        for(int i = 0; i < 8; i++) {
            if(z[i] < x.z[i]) {
                return 1;
            }
            else if(z[i] == x.z[i]) {
                continue;
            }
            else {
                return 0;
            }
        }
    }
}temp[maxn], t_8[maxn], _t_8[maxn];

struct NODE {
    int z[10];
    int x[10];
}res[maxn];

bool cmp(NODE nn, NODE mm) {
    for(int i = 0; i < 8; i++) {
        if(nn.x[i] < mm.x[i]) {
            return 1;
        }
        else if(nn.x[i] == mm.x[i]) {
            continue;
        }
        else {
            return 0;
        }
    }
    return 0;
}

void init() {
    do {
        for(int i = 0; i < 8; i++) {
            temp[tot].z[i] = a[i];
        }
        tot++;
    } while(next_permutation(a, a+8));
    sort(temp, temp+tot);
}

void cal(int n) {
    int aa[10];
    for(int i = 0; i < n; i++) {
        aa[i] = i+1;
    }
    do {
        for(int i = 0; i < n; i++) {
            res[cnt].z[i] = aa[i];
        }
        for(int i = 1; i < n; i++) {
            res[cnt].x[i-1] = res[cnt].z[i] - res[cnt].z[i-1];
            // cout << res[cnt].x[i-1] << "  ";
        }
        // cout << endl;
        cnt++;
    } while(next_permutation(aa, aa+n));
    sort(res, res+cnt, cmp);
}

int main() {
    tot = tot1 = tot2 = 0;
    init();
    int t;
    scanf("%d", &t);
    while(t--) {
        int n, k;
        scanf("%d%d", &n, &k);
        if(n <= 8) {
            cnt = 0;
            cal(n);
            for(int i = 0; i < n; i++) {
                printf("%d%c", res[k-1].z[i], i==n-1?'\n':' ');
            }
        }
        else {
            printf("%d ", n);
            for(int i = 1; i < n-8; i++) {
                printf("%d ", i);
            }
            k = k - 1;
            for(int i = 0; i < 8; i++) {
                printf("%d%c", temp[k].z[i]+n-9, i==7?'\n':' ');
            }
        }
    }
    return 0;
}

【1006】 扩展KMP HDU-6629 string matching

http://acm.hdu.edu.cn/showproblem.php?pid=6629

给定一个字符串,现要求得它的每一个后缀和原串的公共前缀,问暴力执行这一过程需要多少步。

扩展KMP裸题。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 1e6+5;

char s[maxn];
char T[maxn];
ll nxt[maxn], extend[maxn];

void getnxt(char str[]) {
    int i = 0, j, po;
    int len = strlen(str);
    nxt[0] = len;
    while(str[i] == str[i+1] && i+1 < len) i++;
    nxt[1] = i;
    po = 1;
    for(i = 2; i < len; i++) {
        if(nxt[i-po]+i < nxt[po]+po)  // case1 可以直接得到next[i]的值
            nxt[i] = nxt[i-po];
        else {  // case2 要继续匹配才能得到next[i]的值
            j = nxt[po] + po - i;
            if(j < 0)   // 如果i>po+next[po],则要从头开始匹配
                j = 0;
            while(str[j] == str[j+i] && i+j < len) j++;
            nxt[i] = j;
            po = i;
        }
    }
}
void EXKMP(char s1[], char s2[]) {
    int i = 0, j, po;
    int l1 = strlen(s1);
    int l2 = strlen(s2);
    getnxt(s2);
    while(s1[i] == s2[i] && i < l2 && i < l1) i++;
    extend[0] = i;
    po = 0;
    for(i = 1; i < l1; i++) {
        if(nxt[i-po]+i < extend[po]+po)    //case1 直接可以得到extend[i]的值
            extend[i] = nxt[i-po];
        else {  // case2 要继续匹配才能得到extend[i]的值
            j = extend[po]+po-i;
            if(j < 0)   // 如果i>extend[po]+po则要从头开始匹配
                j = 0;
            while(s1[j+i]==s2[j] && i+j < l1 && j < l2) j++;
            extend[i] = j;
            po = i;
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        scanf("%s", s);
        strcpy(T, s);
        EXKMP(s, T);
        int n = strlen(s);
        ll ans = 0;
        for(int i = 1; i < n; i++) {
            ans = ans + extend[i];
            if(extend[i] != n-i) {
                ans = ans + 1;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

【1007】 规律 HDU-6630 permutation 2

http://acm.hdu.edu.cn/showproblem.php?pid=6630

给定 \(n,x,y\),对于 \(1\) 到 \(n\) 这 \(n\) 个数,满足:\(p_1 = x, \ p_2 = y, \ |p_i-p_{i-1}| \leq 2 \ (1 \leq i < n)\)。

打表找规律即可。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;

const int maxn = 1e5+5;

ll a[maxn];

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n, x, y;
        scanf("%d%d%d", &n, &x, &y);
        if(n == 2 || n == 3) {
            printf("1\n");
            continue;
        }
        a[0] = 0;
        if(x == 1) {
            a[1] = 1;
            a[2] = 1;
            for(int i = 3; i <= y-x; i++) {
                if(i == n-x) {
                    a[i] = (a[i-1] + a[i-2] + a[i-3]) % mod;
                }
                else {
                    a[i] = (a[i-1] + a[i-3]) % mod;
                }
            }
        }
        else if(x == n-1) {
            printf("1\n");
            continue;
        }
        else {
            a[1] = 0;
            a[2] = 1;
            for(int i = 3; i <= y-x; i++) {
                if(i == n-x) {
                    a[i] = (a[i-1] + a[i-2] + a[i-3]) % mod;
                }
                else {
                    a[i] = (a[i-1] + a[i-3]) % mod;
                }
            }
        }
        printf("%lld\n", a[y-x]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Decray/p/11330796.html

时间: 2024-08-09 04:01:33

暑假N天乐【比赛篇】 —— 2019杭电暑期多校训练营(第五场)的相关文章

2019杭电多校第九场

2019杭电多校第九场 熟悉的后半场挂机节奏,又苟进首页了,很快乐 1001. Rikka with Quicksort upsolved 不是我做的,1e9调和级数分段打表 1002. Rikka with Cake solved at 01:11 有一个矩形,给你很多射线(射线只有横平竖直的四个方向),问把矩形切成了多少块 队友说答案是交点数加一,作为一个合格的工具人,当然是把队友的想法实现啦 二维坐标离散化枚举纵坐标维护横坐标,常规套路,树状数组也可以做(我是线段树写习惯了根本没想起来还有

2019 杭电多校 第五场

2019 Multi-University Training Contest 5 补题链接:2019 Multi-University Training Contest 5 罚时爆炸 自闭场 1004 equation (HDU 6627) 题意: 给定一个整数 \(C\) 和 \(N\) 组 \(a_i,b_i\),求 \(∑_{i=1}^N|a_i\cdot x + b_i| = C\) 的所有解,如果有无穷多个解就输出 -1. 思路 分类讨论 分类讨论去绝对值.根据 \(b_i / a_i

杭电2018多校第一场(2018 Multi-University Training Contest 1) 1001.Maximum Multiple (HDU6298)-数学思维题(脑子是个好东西,可惜我没有)

暑假杭电多校第一场,这一场是贪心场,很多贪心的题目,但是自己太菜,姿势挫死了,把自己都写吐了... 2018 Multi-University Training Contest 1 HDU6298.Maximum Multiple 题目意思就是给你一个n,找出来三个数x,y,z, 使得n=x+y+z,而且x,y,z都是n的因数,并且x*y*z为最大值,让你输出来x*y*z的最大值.如果没有满足条件的情况就输出-1. 由1=1/2+1/3+1/6=1/3+1/3+1/3=1/2+1/4+1/4,所

2019杭电多校训练(一)

比赛链接: http://acm.hdu.edu.cn/search.php?field=problem&key=2019+Multi-University+Training+Contest+1&source=1&searchmode=source hdu6582 题意: 删除某些边,让$1$到$n$的最短路径发生变化 删除某条边的费用是边的长度 分析: 先用迪杰斯特拉跑一遍整个图,满足$dis[a]+w=dis[b]$的边,肯定是最短路径上的边 选出这些边,找到一个最小割集,Di

2019 杭电多校 第八场

2019 Multi-University Training Contest 8 补题链接:2019 Multi-University Training Contest 8 1003 Acesrc and Good Numbers HDU 6659 题意 定义 \(f(d, n)\) 为十进制下 \(1\) 到 \(n\) 所有数的数位中数字 \(d\) 出现的次数.给定 \(x\),找出最大的 \(n(n \le x)\) 满足 \(f(d, n) = n\). 题解 看到了一个神仙做法. 显

2019 杭电多校 第七场

2019 Multi-University Training Contest 7 补题链接:2019 Multi-University Training Contest 7 1001 A + B = C 题意: 给出 \(a, b, c\),求 \(x, y, z\) 满足 \(a\cdot 10^x + b\cdot 10^y = c\cdot 10^z\).\(a, b, c \le 10^{100000}\). 题解: 补零到 \(a, b, c\) 长度相等之后,可能的情况只有四种: \

2019 杭电多校 第六场

2019 Multi-University Training Contest 6 补题链接:2019 Multi-University Training Contest 6 1002 Nonsense Time (HDU 6635) 题意 给定包含 \(n\) 个不同数字的排列 \(p\).一开始所有数字都冻住.再给出一个长度为 \(n\) 的数组 \(k\),\(k[i]\) 表示 \(p[k[i]]\) 在第 \(i\) 时刻解冻.输出 \(n\) 个数,表示第 \(i\) 个时刻数组 \(

2019 杭电多校 第一场

2019 Multi-University Training Contest 1 补题链接:2019 Multi-University Training Contest 1 1002 Operation (HDU-6579) 题意 给定包含 \(n\) 个数的序列,\(m\) 个询问.询问有两种操作,操作 \(0\) 表示在数组最后添加一个新元素,操作 \(1\) 表示查询区间 [l,r] 的子集的异或最大值. 询问强制在线. 题解 线性基 贪心 1004 Vacation (HDU-6581)

2019 杭电多校 第四场

2019 Multi-University Training Contest 4 补题链接:2019 Multi-University Training Contest 4 1001 AND Minimum Spanning Tree (HDU 6614) 题意 给定一个有 \(N\) 个结点的完全图,编号从 \(1\) 到 \(N\).结点 \(x\) 与结点 \(y\) \((1\leq x, y\leq N, x \neq y)\) 的边的权值为 \(x\) 与 \(y\) 按位与的值,求