目录
- Problem A. Ascending Rating(HDU6319)
- Problem D. Euler Function(HDU6322)
- Problem F. Grab The Tree(HDU6324)
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的也能大体看懂。