A 一个奇妙的旅程
思路
直接输出。
代码
#include <stdio.h>
int main()
{
printf("Have a good day!");
return 0;
}
B 最令人高兴的旅行方案
思路
容易发现两人都喜欢的景点对答案的贡献为 ,只有一个人喜欢的景点对答案的贡献为 ,二人都不喜欢的景点对答案的共享是 ,所以我们只需要统计出有多少个两人都喜欢的景点 ,然后答案即为 。
代码
#include <stdio.h>
int n,x,y;
int cnt[200005];
int main()
{
scanf("%d%d%d",&n,&x,&y);
for (int a,i=1;i<=x;++i)
{
scanf("%d",&a);
cnt[a]++;
}
for (int a,i=1;i<=y;++i)
{
scanf("%d",&a);
cnt[a]++;
}
int ans=0;
for (int i=1;i<=n;++i)
if (cnt[i]==2) ans+=2;
printf("%d\n",ans);
return 0;
}
C 简单博弈游戏
思路
如果 的个位值为 ,则先手必输,否则先手必胜。理由如下:
如果当前剩余的瓜子数的个位 不是 ,就拿走 个瓜子。这样的话如果对手还能进行操作,他操作后剩余瓜子数量的个位一定不是 ,还可以用同样的策略进行操作。直到对手不能进行操作为止。
数据范围较小,如果找不到上述的简单规律也可以用动态规划解决该问题。
代码
#include <stdio.h>
int main()
{
int T,n;
for (scanf("%d",&T);T--;)
if (scanf("%d",&n),n%10==0) printf("Wumeinv\n");
else printf("Ice_teapoy\n");
return 0;
}
D 以fibonacci数列排列的花
思路
奇数+奇数=偶数
奇数+偶数=奇数
所以斐波那契数列的奇偶性为 奇、奇、偶、奇、奇、偶、奇、奇、偶、奇、奇、偶……
所以本题的答案为 。
代码
#include <stdio.h>
int main()
{
int T;
for (scanf("%d",&T);T--;)
{
long long n;
scanf("%lld",&n);
printf("%lld\n",n-n/3);
}
return 0;
}
E 博物馆门票
思路
小学数字题 qwq
输出 。
容易发现买四张门票来打五折相当于不打折,所以我们最多买三张票。所以可能选择的方案有:
- 买两张学生票,答案可以取 。
- 买两张成人票打五折,当 时,答案可以取 。
- 买三张成人票打五折,当 时,答案可以取 。
代码
#include <stdio.h>
#include <algorithm>
using namespace std;
int main()
{
int x,k;
scanf("%d%d",&x,&k);
if (2*x>=k) printf("%.2lf\n",x*1.0);
else if (3*x>=k) printf("%.2lf\n",x*1.5);
else printf("%.2lf\n",x*1.6);
return 0;
}
F 爬山
思路
容易发现并不会来回走……
令 l[i] 表示第 i 座山往左最远能走到哪:
- 如果第 i 座山能去往第 i-1 座山,则 l[i]=l[i-1]+1
- 否则 l[i]=1。
同理求出第 i 座山往右最远能走到哪。两者中的最大值即为答案。
代码
#include <stdio.h>
const int N=200005;
int n,k,a[N];
int l[N],r[N];
int main()
{
scanf("%d",&n);
scanf("%d",&k);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
int ans=1;
l[1]=r[n]=1;
for (int i=2;i<=n;++i)
if (a[i]+k>=a[i-1]) l[i]=l[i-1]+1;
else l[i]=1;
for (int i=n-1;i>=1;--i)
if (a[i]+k>=a[i+1]) r[i]=r[i+1]+1;
else r[i]=1;
for (int i=1;i<=n;++i)
{
if (ans<l[i]) ans=l[i];
if (ans<r[i]) ans=r[i];
}
printf("%d\n",ans);
return 0;
}
G 祈福串珠
思路
性质一
一串串制作等价于同时制作多串。
具体来说,由于蓝桥 A 梦每次都是按序号把珠子给 Ity,当某个珠子不能串在第 个珠串时,Ity 可以直接试图把它串在第 根绳子上,而不必把它还给蓝桥 A 梦等待下一轮制作。
性质二
所有的串串首不增串尾不减。
具体来说,记第 个珠串最左边珠子的大小为 ,最右边珠子的大小为 。则任一时刻有
否则不满足制作规则。
解法
综上所述,对于第 颗珠子大小为 :
- 在 数组中二分一个最小值 满足 。
- 在 数组中二分一个最小值 满足 。
- 若 ,珠子 应该串在第 根绳子的左端,更新 ;若 ,珠子 应该串在第 根绳子的右端,更新 ;否则,珠子 应该串在新的空绳子上。
容易发现更新不会影响数组 和 的单调性,思路类似于最长上升子序列的二分解法。顺便统计答案即可。
update:有群友说直接二分珠子第一个不被包含的珠串就可以了,我感觉非常对,但是代码是我的旧思路懒得改了(
代码
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N=200005;
int n;
int a[N],b[N],tot,cnt[N];
int main()
{
scanf("%d",&n);
for (int i=1,x,aa,bb,l,r,mid;i<=n;++i)
{
scanf("%d",&x);
if (tot==0)
{
cnt[++tot]=1;
a[1]=b[1]=x;
continue;
}
if (a[tot]>x)
{
for (l=1,r=tot;l!=r;)
{
mid=l+r>>1;
if (a[mid]>x) r=mid;
else l=mid+1;
}
aa=l;
}
else aa=tot+1;
if (b[tot]<x)
{
for (l=1,r=tot;l!=r;)
{
mid=l+r>>1;
if (b[mid]<x) r=mid;
else l=mid+1;
}
bb=l;
}
else bb=tot+1;
if (aa==bb)
{
cnt[++tot]=1;
a[tot]=b[tot]=x;
}
else if (aa<bb) a[aa]=x,cnt[aa]++;
else b[bb]=x,cnt[bb]++;
}
int maxx=1;
for (int i=1;i<=tot;++i) maxx=max(maxx,cnt[i]);
printf("%d %d",tot,maxx);
return 0;
}
H 简单的问题
思路
全场最难的题,思路比较长且难想但是没什么超纲知识点于是还是放上来了 qwq
引理一
设 是任意两个不同的有限集合,则 。当且仅当 A 和 B 存在包含关系,且两者元素个数相差 时等号成立。下面给出证明:
令
则
带入原式可得
当且仅当 和 分别为 和 时,等号成立。
引理二
记 的全部子集为 ,则一定存在 的一个排列 使得 和 存在包含关系,且元素数量之差为 。下面给出证明:
当 时,集合 的四个子集排列成 即可满足条件。
假设命题对 成立,且 是一个满足条件的排列,则对于 ,取以下排列方式即可满足条件:
由数学归纳法,命题得证。
引理三
证明如下:
综上所述:
由引理一可知
使用引理二中的排列方法可以使得等号成立,又由引理三可知, 的最大值为
所以本题的答案为对每个询问的 ,输出 即可。
代码
#include <stdio.h>
using namespace std;
using LL=long long;
const LL mod=1e9+7;
LL poww(LL a,LL b)
{
a%=mod;
LL ans=1;
for (;b;b>>=1,a=a*a%mod)
if (b&1) ans=ans*a%mod;
return ans;
}
int main()
{
int T;
LL n,t;
for (scanf("%d",&T);T--;)
{
scanf("%lld",&n);
if (n==1)
{
printf("0\n");
continue;
}
t=poww(2,n-2);
n%=mod;
printf("%d\n",(n*n%mod+n+mod-2)%mod*t%mod);
}
return 0;
}
I 种瓜得瓜,种豆得豆
思路
第 棵气球当前的美味度是 ,我们令 表示第 棵气球的最佳收获期限,同时也是最后收获期限。
从 到 枚举当前时刻 ,此时我们可以选择收获所有满足 的没有在未来被收获的气球。假设我们选择此刻收获气球 ,那么对答案的贡献显然为 ,为了最大化答案,应该选择收获 值最小的气球。
对 数组进行过排序,枚举当前时刻 的同时双指针将符合条件 的气球压进栈里,每个时刻收获栈顶的气球即可。
代码
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <math.h>
using namespace std;
const int N=200005;
using LL=long long;
LL ans;
int a[N],b[N],stk[N],n,p,k;
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=k-a[i];
sort(b+1,b+1+n);
for (int t=k-1,j=n;t>=0;--t)
{
while (j>=1&&b[j]>=t) stk[++p]=b[j--];
if (p) ans+=k-stk[p--]+t;
}
printf("%lld\n",ans);
return 0;
}
J 数组划分
思路
对 进行分类讨论:
- 若 则无法将任何元素分离成一个单独子段,故取所有元素最小值。
- 若 则可以将第一个元素或者最后一个元素分离成单独的一个子段,故取第一个和最后一个的较大值。
- 若 则可以分离出任何一个元素作为单独的子段,故取所有元素最大值。
发现数据水了被一堆人直接输出数组最大值碾过(
代码
#include <stdio.h>
int a[200005];
int main()
{
int n,k,minn=1e9+1,maxx=0;
scanf("%d%d",&n,&k);
for (int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if (a[i]>maxx) maxx=a[i];
if (a[i]<minn) minn=a[i];
}
if (k>=3) printf("%d",maxx);
else if (k==1) printf("%d",minn);
else if (a[1]>a[n]) printf("%d",a[1]);
else printf("%d",a[n]);
return 0;
}
总结
榜单看上去不太丑,前排很有区分度 qwq
但是中档题略少,看起还还是让相当一部分同学在赛中感到无聊了对不起 orz
不太想出原题或者板子题,所以看起来可能会有点像是脑筋急转弯 orz
发现有部分同学完全不理解多测(在一个测试点中输入 组测试数据),导致本来可以做出的题写不出来,非战之罪,也很对不起(
本来以为昨天赛中没有什么锅的但是今天又查看代码才发现 J 数据弱了orz