2018 Multi-University Training Contest 3 - (A,D,F)

        目录


                                  Problem A. Ascending Rating(HDU6319)

题意:有序列a1~an,对于每个连续的长为m的子区间[aL,aL+m-1],求两个值:maxrating和count,两者初始值均为0,从左到右扫描每个元素,如果有元素大于maxrating,则更新maxrating且让count++。求出每个区间的maxrating和count后,再按题给公式求出A和B。

解析:题目挺不错的,比赛时想到了用单调队列,但没想到是从后往前维护单调队列,而且只用维护一个单调队列即可求值,我才开始的思路只是从前往后维护,这样的话,单调队列只能作为整体的一部分,整体复杂度还是很大,所以也没多想。

正确做法是:从an~a1维护一个严格递减的单调队列,对于每个区间在单调队列已经维护好的情况下,maxrating就是队首元素、队中元素个数就是count。

题解中的解释

  •       按照 r 从 m 到 n 的顺序很难解决这个问题。
  •       考虑按照 r 从 n 到 m 的顺序倒着求出每个区间的答案。
  •       按照滑窗最大值的经典方法维护 a 的单调队列,那么队列 中的元素个数就是最大值的变化次数。
  •       时间复杂度 O(n)。

代码

#include<cstdio>
const int N=10000010;

int T,n,m,k,P,Q,R,MOD;
int i,a[N],q[N],h,t;//q是单调队列
long long A,B;

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d%d%d%d",&n,&m,&k,&P,&Q,&R,&MOD);

        for(i=1;i<=k;i++)
            scanf("%d",&a[i]);

        for(i=k+1;i<=n;i++)
            a[i]=(1LL*P*a[i-1]+1LL*Q*i+R)%MOD;

        //h是队首,t是队尾
        for(h=1,t=A=B=0,i=n;i;i--)
        {
            while(h<=t&&a[q[t]]<=a[i]) t--;//队列递减所以队尾上小于要插入值的元素都删除
            q[++t]=i;
            if(i+m-1<=n)//i可以作为区间起点了
            {
                while(q[h]>=i+m) h++;//去掉区间外的元素
                A+=i^a[q[h]];
                B+=i^(t-h+1);
            }
        }
        printf("%lld %lld\n",A,B);
    }
    return 0;
}

 

                                 Problem D. Euler Function(HDU6322)

题意:给定 k,求第 k 小的数 n,满足 φ(n) 是合数。

解析:我是打表发现规律,然后回想到之前做过的一道数论题有证明过,一个数的小于它且与它互质的数是成对出现的。

只有 φ(1) φ(2) φ(3) φ(4) φ(6)不是合数。

题解中的证明

  • 显然 φ(1) = 1 不是合数,只考虑 n ≥ 2 的情况。
  • 设 n = p1^k1*p2^k2...pm^km,则 φ(n) = [p1^(k1−1)]*(p1 − 1)  *  [p2^(k2−1)]*(p2 − 1)...[pm^(km−1)]*(pm − 1)。
  • 若 2 的指数不超过 1,那么 2 不影响 φ(n) 的素性。
  • 若 2 的指数为 2,那么对 φ(n) 贡献一个 2。
  • 若 2 的指数 ≥ 3,那么对 φ(n) 至少贡献一个 4,此时 φ(n) 一定是合数。

 

  • 对于除 2 之外的质数 p,如果指数 ≥ 2,那么至少贡献了 (p − 1)p。
  • 如果除 2 之外还有至少两个质数 p, q,那么至少贡献了 (p − 1)(q − 1)。
  • 所以这两种情况下 φ(n) 一定是合数。

 

  • 剩下的情况只能是以下几种之一,(即2的指数≤2与只有另一个质因数p指数≤1的组合), 其中 p 是大于 2 的质数:
  • n = 2, 4,显然是素数。
  • n = p,当 p > 3 时一定是偶合数,而当 p = 3, n = 3 时是 偶素数。 (n为素数则φ(n)=n-1)
  • n = 2p,同理当 p > 3 时一定是偶合数,而当 p = 3, n = 6 时是偶素数。
  • n = 4p,那么 φ(n) 中至少有两个 2,所以一定是合数。

 

  • 综上所述,当且仅当 n = 1, 2, 3, 4, 6 时,φ(n) 不是合数。
  • ans(k) = k + 4 + [k > 1]。 时间复杂度 O(1)。

代码

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int T,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&k);
        if(k==1)
            printf("5\n");
        else if(k==2)
            printf("7\n");
        else
            printf("%d\n",k+5);
    }
    return 0;
}

 

                                Problem F. Grab The Tree(HDU6324)

题意:给定一棵 n 个点的树,每个点有权值。两个人玩游戏,先 手需要占领若干不相邻的点,然后后手占领剩下所有点。 每个人的得分为占领的点权异或和,分高的获胜。问最优策 略下游戏的结果。

题解中的解析

  • 设 sum 为所有点权的异或和,A 为先手得分,B 为后手得 分。
  • 若 sum = 0,则 A = B,故无论如何都是平局。
  • 否则考虑 sum 二进制下最高的 1 所在那位,一定有奇数个点那一位为 1。
  • 若先手拿走任意一个那一位为 1 的点,则 B 该位为 0,故先手必胜。
  • 时间复杂度 O(n)。

代码

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

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);

        int w,sum,u,v;
        scanf("%d",&w);
        sum=w;
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&w);
            sum=sum^w;
        }
        for(int i=1;i<n;i++)
            scanf("%d%d",&u,&v);

        if(sum==0) printf("D\n");
        else printf("Q\n");
    }
    return 0;
}

 

最后:Problem C. Dynamic Graph Matching是一道状态压缩DP,会状压的应该一看题解就明白了,我看到有一篇博客https://blog.csdn.net/winter2121/article/details/81293935写的不错,对于还不太了解状压DP的也能大体看懂。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值