版权声明:欢迎评论交流,转载请注明原作者。 https://blog.csdn.net/m0_37809890/article/details/83187913
上上次看错卡简单题,上次想偏卡中期题,这次卡了脑洞题,三场掉蓝,RP=max。
总结
- 简单的计算题最好先在纸上列出算式,并且算一下样例,不要直接上手。
- 构造题,先写一个正向的程序来找思路,最后也可以拿它来检验。
如果能正常跑完正向程序的话,除了值域与正向程序之外不用再写其它判断构造失败的条件。 - 看到区间求和有关的东西,就自动去想前缀和了!
A. Elevator or Stairs? 计算
当前在x层,要去y层(x≠y),可以选择走楼梯或者电梯。当前电梯在z层,电梯移动一层花费t2时间,电梯开门或者关门需要t3时间,走一层楼梯需要t1时间。当使用电梯的时间小于使用楼梯的时间时,输出YES,vice versa。
走楼梯时间
坐电梯时间
,需要开门两次,关门一次
列好算式,比较即可。
B. Appending Mex 模拟
定义mex()函数,输入一个可重集合,返回集合中最小的未出现的非负整数。
维护一个集合,初始时刻为空,每次操作选取它的一个子集求mex并将结果添加到集合最后。
现在给出一个集合,问是否可以通过上边的操作形成的,如果不行,输出最早的假的步数。
模拟,维护当前集合中的最大值即可。
C. Candies Distribution 构造
n(1000)个数的序列,告诉每个位置的左边有多少有多少个比它的值大的,右边有多少个比它的值大的,求是否有这样的序列,要求值域在1到n之间。
把左和右加起来,就知道了有多少个数大于这个数了,这个位置的值就是n-lef[i]-rig[i]。最后检验一下答案是否正确。
int lef[M],rig[M],ans[M];
int main(void)
{
int n = read();
for(int i=1;i<=n;++i)
lef[i] = read();
for(int i=1;i<=n;++i)
rig[i] = read();
for(int i=1;i<=n;++i)
ans[i] = n-lef[i]-rig[i];
int fail = 0;
for(int i=1;i<=n;++i)
{
int xl=0,xr=0;
for(int j=1;j<=n;++j) if(ans[j]>ans[i])
{
if(j<i) ++xl;
if(j>i) ++xr;
}
if(xl!=lef[i] || xr!=rig[i])
fail = 1;
}
if(fail)
printf("NO\n");
else
{
printf("YES\n");
for(int i=1;i<=n;++i)
printf("%d ",ans[i] );
printf("\n");
}
return 0;
}
D. Changing Array 前缀和
给定n(2e5),k(30),和n个k位数组成的序列。在每个数都可以任意取反的情况下,求最多有多少子串异或和不为0.
如果序列不变,怎么求有多少子串异或和不为0?
,其中
,即前缀异或和。
所以答案就是n*(n-1)/2 - 所有值出现的次数分别组合 - 为0的前缀和个数。(不想写数学公式了)
如果每个数可以取反,那么每个前缀和也可以取反。把取反后相同的前缀和尽量平均地分配即可,注意0与~0时,要把0的个数减去。
n*n会爆int
/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 500016, MOD = 1000000007;
int save[M];
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int n = read(), k = read();
for(int i=1;i<=n;++i)
save[i] = read()^save[i-1];
int mx = (1<<k)-1;
map<int,int> mp;
for(int i=1;i<=n;++i)
++mp[min(save[i],mx-save[i])];
ll ans = (ll)n*(n+1)/2;
for(auto pii:mp)
{
ll a = pii.second/2, b = (pii.second+1)/2;
ans -= a*(a-1)/2 + b*(b-1)/2;
if(pii.first==0)
ans-=a;
}
printf("%I64d\n",ans );
return 0;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}