Brooklyn Round 2 & NNOI Round 2 旧账 题解 8.26
为什么要写有中文官解的比赛题解?
不知道,就当自己总结一下好了
A
要求中位数最小,肯定前 \((n+1)/2\) 个选较小的,后面的选最大的
这样可以保证整体最优
CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int n,m;
int a[maxn];
int main(){
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+n+1);
LL ans=0;
int k=(n/m+1)/2;
for(int i=1;i<=m;i++){
ans+=a[i*k];
}
printf("%lld",ans);
return 0;
}
//^o^
B
跑双指针就可以了
注意每次跑完指针统计的是以当前左指针为起点的区间个数
发现区间中的贡献应该是这样的(例区间长度为 \(5\))
\[5 \times A_l + 4 \times A_{l+1} + 3 \times A_{l+2} + 2 \times A_{l+3} + 1 \times A_{l+4}
\]
所以减去左指针的点时应减去其当前区间的长度乘上它的值的贡献
这种时候也可以用前缀和的前缀和直接计算
值域较大,用数组作桶的话需要离散化
CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
const int mod=1e9+7;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
return;
}
int n,m;
int a[maxn],t[maxn];
LL sum[maxn];
vector<int> v;
void ls(){
for(int i=1;i<=n;i++) v.push_back(a[i]);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
m=v.size();
for(int i=1;i<=n;i++){
a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
}
}
int main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
sum[i]=(a[i]+sum[i-1])%mod;
}
ls();
int r=1;
LL ans=0,s=0;
for(int i=1;i<=n;i++){
while(r<=n&&(!t[a[r]])){
s=(s+sum[r]-sum[i-1]+mod)%mod;
++t[a[r++]];
}
ans=(ans+s)%mod;
s=(s-1ll*(r-i)*v[a[i]-1]%mod+mod)%mod;
--t[a[i]];
}
printf("%lld",ans);
return 0;
}
//^o^
C
C和D都是数学分类讨论
象从 \((1,1)\) 点出发,发现它只能到达 \(x,y\) 均为奇数的点
若 \(x,y\) 不相等时,则一定时这样走了:

此时同坐标一次只能增加四格,那么可以得到 \(x ≡ y \, \, \,(mod \, \, 4)\)
若 \(x,y\) 合法,则可以得到需要走 \(max(x,y)/2\) 步能够到达
考虑敌方将军,发现四格内至多有一格满足条件
所以还需要计算敌方将军在象达到时需要走几步才能移到被吃的位置,然后加上这个值
由于是象先手,所以这个值显然需要加 \(1\)
代码参考了这篇题解,代码简洁明了
CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef unsigned long long LL;
void read(LL& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
return;
}
LL n,m;
int main(){
read(n),read(m);
LL add;
if((n&1)&&(m&1)) add=1;
else if((!(n&1))&&(m&1)) add=2,--n;
else if((n&1)&&(!(m&1))) add=0,--m;
else add=3,--n,--m;
if(n%4!=m%4){
printf("-1");
return 0;
}
LL ans=max(n,m)>>1;
ans+=(add+4-(ans%4))%4;
printf("%lld",ans);
return 0;
}
//^o^
D
手推一下斐波那契数列,发现其一定是这样的奇偶性构造
奇,奇,偶,奇,奇,偶,奇,奇,偶...
若只考虑刚好包含 \(n\) 个奇奇偶三元组,则其计算式子显然
\[\frac{2n(2n-1)}{2}+\frac{n(n-1)}{2}
\]
设其等于 \(a\)
化简,得
\[5n^2-3n-2a=0
\]
解出 \(n\)
\[\frac{3+\sqrt{40a+9}}{2}
\]
另外一个解小于 \(0\) ,显然舍去
先向下取整算出有多少个三元组,然后考虑有多余的情况
多一个奇数,多一个偶数,多一个奇数和一个偶数,多两个奇数
分别讨论即可,详见代码
CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef unsigned long long LL;
void read(LL& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
return;
}
LL q,n;
int main(){
read(q);
while(q--){
read(n);
LL p=((int)sqrt(40*n+9)+3)/10;
LL r=(p*p*5-p*3)/2;
if(n==0) printf("%d %d",1,1);
else if(r==n) printf("%d %lld",1,p*3);//没多
else if(r+2*p==n) printf("%d %lld",1,p*3+1);//多一个奇数
else if(r+p==n) printf("%d %lld",3,p*3+3);//多一个偶数
else if(r+3*p==n) printf("%d %lld",3,p*3+4);//多一个奇数,一个偶数
else if(r+4*p+1==n) printf("%d %lld",1,p*3+2);//多两个奇数
else printf("-1");
putchar('\n');
}
return 0;
}
//^o^

浙公网安备 33010602011771号