2019暑假多校训练第五场 | 部分题解

梦月场(出题人是dreamoon 台湾人)

所以题解都是繁体字还有聊天记录hhh

感觉都是数学题啊QAQ

题解链接: https://pan.baidu.com/s/1bJb8UPlgkahMTxpkdpyOPw 提取码: 6j4x 复制这段内容后打开百度网盘手机App,操作更方便哦

 

06 string matching

HDU 6629 扩展KMP

Alone做的

是模板题 记得用long long

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e6+5;
char s[maxn];
long long ne[maxn];
void pre_EKMP(char x[],long long m,long long next[])
{
    next[0]=m;
    long long j=0;
    while(j+1<m&&x[j]==x[j+1]) j++;
    next[1]=j;
    long long k=1;
    for(long long i=2;i<m;i++)
    {
        long long p=next[k]+k-1;
        long long L=next[i-k];
        if(i+L<p+1) next[i]=L;
        else
        {
            j=max((long long)0,p-i+1);
            while(i+j<m&&x[i+j]==x[j]) j++;
            next[i]=j;
            k=i;
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s);
        long long len=strlen(s);
        pre_EKMP(s,len,ne);
        long long sum=0;
        for(long long i=1;i<len;i++)
        {
            if(ne[i]==0)
                sum++;
            else
            {
                sum+=ne[i];
                if(ne[i]+i<len)
                    sum++;
            }
        }
        //printf("\n");
        printf("%lld\n",sum);
    }
    return 0;
}

 

07 permutation 2

HDU 6630 推公式

证明

 

感谢桑老师借我平板写过程orz

(平板真好玩)

AC代码如下:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll mod = 998244353;
ll a[200005];

int main()
{
    a[0] = 0;
    a[1] = 1;
    a[2] = 1;
    a[3] = 1;
    a[4] = 2;
    a[5] = 3;
    a[6] = 4;
    a[7] = 6;
    a[8] = 9;
    for (int i = 8; i < 200005; i++) {
        a[i] = (a[i - 3] % mod + a[i - 1] % mod ) % mod;
    }
    int t, n, x, y;
    ll L, R;
    scanf("%d", &t);
   // printf("%lld\n", a[50629]);

    while (t--) {
        scanf("%d%d%d", &n, &x, &y);
        if (x == 1) {
            L = 1;
        } else {
            L = x + 1;
        }
        if (y == n) {
            R = n;
        } else {
            R = y - 1;
        }
        printf("%lld\n", a[R - L + 1]);
    }
    return 0;
}

 

04 equation

HDU 6627 数学题

题目大意:给出下列式子的C,M,ai,bi,

\sum_{i=1}^ {M} \left |ai*x+bi \right | = C

求 x 的所有解

如果无解输出 0,有无穷解就输出 -1

其他情况就是输出解的个数以及解的分数形式(0 输出 0/1)

解决方法:先将所有的ai系数相加,所有的bi的系数相加

x1,x2,x3,……xm从小到大排序 (a1*x1+b1=0时成立)

得到 n+1 个区间

枚举所有区间的解 判断该解是否在区间内,存到数组中记录

#include <stdio.h>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct node {
    int a, b;
    double x;
    int id;
} mm[100050], ans[100050];
queue<node>q;
int A[100050], B[100050];
int sum_a = 0, sum_b = 0, n, c, f, num;
double l, r;
int gcd(int a,int b)
{
    return b? gcd(b,a%b):a;
}
bool cmp(node xx, node yy)
{
    if (xx.x != yy.x) {
        return xx.x < yy.x;
    } else {
        return xx.id < yy.id;
    }
}

void run()
{
    if (sum_a == 0 && sum_b == c) {
        f = 1;
        return ;
    }
    double aa;
    aa = (double)(c - sum_b)/sum_a;
    if (aa > l && aa <= r) {
        int as = 1;
        if (aa < 0) {
            as = -1;
        }
        int xx = abs(c - sum_b), yy = abs(sum_a);
        int zz = 0;
        if (xx == 0) {
            zz = yy;
        } else {
            zz = gcd(xx, yy);//自带gcd,尽量少用
        }
//        node k ;
//        k.a = xx / zz * as;
//        k.b = yy / zz;
//        q.push(k);
        ans[num].a = xx / zz * as;
        ans[num].b = yy / zz;
        num++;
    }
    return;
}
int main()
{
    int t;
    scanf("%d", &t);
    while (t--) {
//        while (!q.empty()) {
//            q.pop();
//        }
        memset(A, 0, sizeof A);
        memset(B, 0, sizeof B);
        f = 0;
        sum_a = 0, sum_b = 0;
        scanf("%d%d", &n, &c);
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &A[i], &B[i]);
            mm[i].a = A[i];
            mm[i].b = B[i];
            mm[i].id = i;
            mm[i].x = (double)B[i] / A[i] * (-1.0);
            sum_a -= A[i];
            sum_b -= B[i];
        }
        sort(mm, mm + n, cmp);
        num = 0;
        l = -1e15, r = -1e15;
        mm[n].x = 1e15;
        for (int i = 0; i <= n; i++) {
            l = r, r = mm[i].x;
            if (f != 1) {
                run();
            }
            sum_a += mm[i].a * 2;
            sum_b += mm[i].b * 2;
        }
        if (f == 1) {
            printf("-1\n");
        } else {
//            printf("%d",q.size());
            printf("%d", num);
            for (int i = 0; i < num; i++) {
//            for (int i = 0; i < q.size(); i++) {
//                while (!q.empty()) {
//                    node k = q.front();
//                    q.pop();
//                    printf(" %d/%d", k.a, k.b);
                printf(" %d/%d", ans[i].a, ans[i].b);
//                }
            }
            printf("\n");
        }
    }
    return 0;
}

 

05 permutation 1

HDU 6628 全排列

关于全排列函数 next_permutation() 的使用 参考:https://blog.csdn.net/AC_Gibson/article/details/45308645

题目大意:询问 T 次,求出1~ N 的全排列中以相邻元素之差字典序从小到大排序的第 K 个序列。

 

 

 

08

HDU 几何

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值