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\) 排序,可得各段区间:\([-b_0/a_0, ∞),\ [-b_1/a_1, -b_0/a_0),\ [-b_2/a_2, -b_1/a_1),\ ...\ ,[-b_n/a_n, -b_{n-1}/a_{n-1}),\ [∞, -b_n/a_n)\) 设 \(suma = \sum_{i=1}^Na_i, sumb = \sum_{i=1}^Nb_i\),依次让 \(a_ix+b_i\) 变成 \(-a_ix-b_i\),也就是 \(suma - 2a_i, sumb-2b_i\),求出 \(x_i = \frac{c - sumb}{suma}\) 并判断是否在区间内。无穷解的情况:\(suma = 0, sumb = c\)。

感谢杭电没有卡 \(double\)。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn = 1e5 + 10;

typedef long long ll;

struct Coefficient {
    ll a, b;
} co[maxn];

int cmp(Coefficient c1, Coefficient c2) {
    return c1.b * 1.0 / c1.a < c2.b * 1.0 / c2.a;
}

vector<Coefficient> ans;

ll gcd(ll a, ll b) {
    return b == 0? a: gcd(b, a % b);
}

int main() {
    int T;
    cin >> T;
    while(T--) {
        ans.clear();
        int n;
        ll c;
        scanf("%d%lld", &n, &c);
        ll suma = 0, sumb = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%lld%lld", &co[i].a, &co[i].b);
            suma += co[i].a;
            sumb += co[i].b;
        }
        sort(co + 1, co + n + 1, cmp);
        Coefficient t;
        t.a = suma, t.b = sumb;
        if((c - sumb) * 1.0 / suma >= -co[1].b * 1.0 / co[1].a) {
            t.b = c - t.b;
            ans.push_back(t);
        }

        int flag = 1;
        for(int i = 1; i <= n; ++i) {
            suma -= co[i].a * 2;
            sumb -= co[i].b * 2;
            t.a = suma;
            t.b = sumb;
            if(!suma) {
                if(sumb == c) {
                    flag = 0;
                    break;
                }
            }
            if(i < n) {
                if((c - sumb) * 1.0 / suma >= -co[i + 1].b * 1.0 / co[i + 1].a && (c - sumb) * 1.0 / suma < -co[i].b * 1.0 / co[i].a) {
                    t.b = c - t.b;
                    ans.push_back(t);
                }
            } else {
                if((c - sumb) * 1.0 / suma < -co[i].b * 1.0 / co[i].a) {
                    t.b = c - t.b;
                    ans.push_back(t);
                }
            }
        }

        if(!flag) printf("-1\n");
        else {
            sort(ans.begin(), ans.end(), cmp);
            printf("%d", ans.size());
            for(int i = 0; i < ans.size(); ++i) {
                if(ans[i].b * 1.0 / ans[i].a < 0) printf(" -");
                else printf(" ");
                ll g = gcd(abs(ans[i].b), abs(ans[i].a));
                if(ans[i].b == 0) printf("0/1");
                else printf("%lld/%lld", abs(ans[i].b) / g, abs(ans[i].a) / g);
            }
            printf("\n");
        }

    }
    return 0;
}

1005 permutation 1 (HDU 6628)

题意:

定义排列 \(p_1, p_2, ... , p_n\) 的 "difference sequence" 为 \(p_2-p_1, p_3-p_2,...,p_n-p_{n-1}\)。现在给定 \(N\) 和 \(K\),求长度为 \(N\) 的所有排列中 "difference sequence" 的字典序第 \(K\) 小的排列。

题解:

暴力 STL 全排列

题目给定 \(K\) 的范围不超过 \(10^4\),而 \(8! = 40320 > K\),因此可以预处理 \(N <= 8\) 的情况,当 \(N > 8\) 时暴力求 \(a[1] = n\) 的全排列。

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

const int maxn = 1e5 + 10;

struct P {
    int num[10];
    string str;
} ans[10][maxn];

int cmp(P p1, P p2) {
    return p1.str < p2.str;
}

int main() {
    int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
    for(int i = 2; i <= 8; ++i) {
        int cnt = 1;
        do {
            // for(int j = 0; j < i; ++j) {
            //     cout << a[j] << " ";
            // }
            // cout << endl;
            for(int j = 1; j <= i; ++j) {
                ans[i][cnt].num[j] = a[j];
                if(j < i) ans[i][cnt].str += a[j + 1] - a[j] + 'A';
            }
            ++cnt;
        } while(next_permutation(a + 1, a + 1 + i));
        sort(ans[i] + 1, ans[i] + cnt, cmp);
        // for(int j = 1; j < cnt; ++j) { for(int k = 1; k <= i; ++k) cout << ans[i][j].num[k] << ""; cout << endl;}
    }
    int T;
    cin >> T;
    while(T--) {
        int n, k;
        scanf("%d%d", &n, &k);
        if(n <= 8) {
            for(int j = 1; j <= n; ++j) {
                printf("%d", ans[n][k].num[j]);
                printf("%s", j == n? "\n": " ");
            }
        } else {
            int a[30];
            a[1] = n;
            for(int i = 2; i <= n; ++i) {
                a[i] = i - 1;
            }
            for(int i = 0; i < k - 1; ++i) {
                next_permutation(a + 1, a + 1 + n);
            }
            for(int i = 1; i <= n; ++i) {
                printf("%d", a[i]);
                printf("%s", i == n? "\n": " ");
            }
        }
    }
    return 0;
}

1006 string matching (HDU 6629)

题意

给定字符串 \(s[0...len - 1]\),对于每个 \(i > 0\),用下图的程序求 \(s[i...len - 1]\) 与 \(s[0...len - 1]\) 的最长公共前缀的长度时,字符比较的操作进行了几次?

题解

扩展KMP/Z函数

签到题,扩展KMP (Z函数) 的裸题,cin 被卡了,改成 scanf 就过了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[1000010];

// Z函数
vector<int> z_function() {
    int n = strlen(s);
    vector<int> z(n);
    for (int i = 1, l = 0, r = 0; i < n; ++i) {
        if (i <= r)
            z[i] = min(r - i + 1, z[i - l]);
        while (i + z[i] < n && s[z[i]] == s[i + z[i]])
            ++z[i];
        if (i + z[i] - 1 > r)
            l = i, r = i + z[i] - 1;
    }
    return z;
}

int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%s", s);
        vector<int> v = z_function();
        ll ans = 0;
        int len = v.size();
        for(int i = 1; i < len; ++i) {
            if(i == len - 1) {
                ans += 1;
                break;
            }
            if(v[i] + i >= len) ans += v[i]; // while 循环中 i + k >= len 就退出循环了
            else ans += v[i] + 1; // otherwise 语句,多比较一次才退出
        }
        printf("%lld\n", ans);
    }
}

1007 permutation 2 (HDU 6630)

\(solved\ by\ ch\)

题意

给定三个正整数 \(N, x, y\),求 \(1 \sim N\) 的全排列中满足下列条件的个数。

  1. \(p_1 = x\)
  2. \(p_N = y\)
  3. 对于所有 \(1 \le i < N,\ |p_i - p_{i + 1}|\le 2\)

题解

DP/动态规划

特殊情况有点多,WA 了好几次。

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

typedef long long ll;

const ll mod = 998244353;

const int maxn = 1e5 + 10;

ll dp[maxn] = {1, 1, 2, 3, 4};

int main() {
    for(int i = 5; i < maxn; ++i) {
        dp[i] = (dp[i - 1] + dp[i - 3]) % mod;
        // if(i <= 20)cout << dp[i] << endl;
    }
    int T;
    cin >> T;
    while(T--) {
        ll n, x, y;
        scanf("%lld%lld%lld", &n, &x, &y); // cout << dp[0] << endl;
        // cout << (dp[y - 1] - dp[x] + mod) % mod << endl;
        if(y - x == 1 && n > 3 && x == 1) printf("1\n");
        else if(y - x == 1 && n > 3 && y == n) printf("1\n");
        else if(y - x == 1 && n > 3) printf("0\n");
        else if(n <= 4) printf("%lld\n", dp[y - x - 1]);
        else if(y - x == 2) printf("1\n");
        else if(x == 1 && y == n) printf("%lld\n", dp[y - x - 1]);
        else if(x == 1 || y == n) printf("%lld\n", dp[y - x - 2]);
        else printf("%lld\n", dp[y - x - 3]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wulitaotao/p/11428320.html

时间: 2024-09-29 18:24:54

2019 杭电多校 第五场的相关文章

[2019杭电多校第五场][hdu6629]string matching

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6629 题意求字符串的每个后缀与原串的最长公共前缀之和. 比赛时搞东搞西的,还搞了个后缀数组...队友一说扩展kmp我都自闭了,这不就是扩展kmp的第一步,求原串的每个后缀与原串的最长公共前缀嘛. 需要注意的就是题目准确问的是按照文中所给的代码执行需要判断几次,如果最长公共前缀等于该后缀的长度,则会判断Next[i]次(Next[i]为以i为开始的后缀与原串的最长公共前缀).如果不等,则会判断Next

[2019杭电多校第五场][hdu6625]three arrays(01字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6625 大意为给你两个数组a和b,对应位置异或得到c数组,现在可以将a,b数组从新排序求c数组,使得字典序最小. 大致的做法就是用两个数组中的数字二进制 建两颗字典树,同时记录每个位置的个数.然后在两颗字典树上同时dfs,优先往0-0和1-1方向走,不能走再走0-1,1-0方向. 因为0-0和1-1两种情况不分先后,所以走出来的不一定是最小的,走完得到的c数组要排序. 1 #include<iostr

[2019杭电多校第五场][hdu6628]permutation 1

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6628 题意为求字典序第k小的差异数组,差异数组p满足p[i]=a[i+1]-a[i]. 头铁的爆搜,因为差异数组的范围为[1-n,n-1],所以爆搜的时候可以先将原数组每位+n,记录数字出现的上下界,最后求答案的时候再减去下界即可. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using n

[2019杭电多校第五场][hdu6624]fraction

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6624 题意为求最小的b满足$a*b^{-1}\equiv x(modp)$. 把式子化简一下: $a\equiv b*x(modp)$ $a=b*x-p*y$ $\because 0<a<b$ $\therefore 0<b*x-p*y<b$ $0<b*x-p*y\Rightarrow \frac{p}{x}<\frac{b}{y}$ $b*x-p*y<b\Right

[2019杭电多校第五场][hdu6630]permutation 2

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6630 题意为求出1-n,n个数的全排列中有多少种方案满足第一位为x,第n位为y,且相邻数字绝对值之差不超过2. 我们可以预处理d数组,定义d[i]表示1-i个数的全排列中以1为第一位,i为第i位且相邻数字绝对值之差不超过2的方案数. 则第i位为i,可以由第i-1位转移,表示i位与i-1位数字绝对值之差为1,则$d[i]+=d[i-1]$,也可以由第i-3位转移,表示第i-1位为i-2,第i-2位为i

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\) 按位与的值,求

[补]2019HDU杭电多校第五场H

红小豆又被奇怪的东西卡住了 参考于:思路https://www.cnblogs.com/st1vdy/p/11309280.html 样例https://www.cnblogs.com/dd-bond/p/11308155.html HDU-6631 line symmetric 多边形轴对称类问题.关于多边形轴对称目前可以公开的情报可见第一篇blog的大佬画的图,主要就是奇偶问题.本题主要思路是枚举实现找轴和验证对称,注意判自交的方式. 初步认识可以做一下hdu3902. 在下还是专注于讲心路

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\) 长度相等之后,可能的情况只有四种: \