2023/3/25 考试总结
在一场 4 个半小时,3 道题的考试中,获得了两位数的好成绩
题目来自 \(2020\ Day1\).
First of all
本次考试难度较高,由于时间相对充沛,所以时间规划比较随意。
主要问题发生在一些基础知识的遗忘。
P6619 [省选联考 2020 A/B 卷] 冰火战士
-
没想到啊,居然是树状数组……
-
考场上打了个 \(\mathtt{priority\_queue}\) 直接模拟挑选 \(T_0\),本来以为复杂度差不多的,然后拿到了暴力分(
-
冰组 (\(ice\)) 的可使用能量其实就是 \(<T_0\) 的 \(E\) 的前缀和,同理火组 (\(fire\)) 的可使用能量就是 \(>T_0\) 的后缀和;
容易想到用树状数组统计,然后二分结果然而我没有想到树状数组,这样的复杂度是 \(O(n\log^2 n)\),可以得到 \(\mathtt{60pts}\); -
优化:
尝试将原来二分答案的 \(\log n\) 的复杂度消掉。
考虑倍增,设起始位置 \(p\),步长 \(d\)。由树状数组的性质可以知道,\(c_{p+d}\) 这个位置恰好存储了 \([p+1,p+d]\) 区间的和。因此可以考虑使用倍增的思想来求解 \(p_0\) 的位置,这样每次加上步长的时候就不需要 \(\log n\) 的复杂度了。
AC code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10+int(ch-'0');
ch=getchar();
}
return s*f;
}
inline void write(int x){
if(!x) return ;
write(x/10);
putchar(x%10+'0');
return ;
}
const int N=2e6+10;
int Q;
int E1=0;
int b[N],tn=0,bl;
int ice[N],fire[N];
struct memr{
int tp,T,E,id;
bool operator<(const memr &_)const{
return T<_.T;
}
}a[N];
void add(int *c,int x,int v){
for(;x<=bl;x+=x&-x)
c[x]+=v;
return ;
}
int ask(int *c,int x){
int cnt=0;
for(;x;x-=x&-x)
cnt+=c[x];
return cnt;
}
int main(){
// freopen("icefire.in","r",stdin);
// freopen("icefire.out","w",stdout);
Q=read();
int opt,x;
for(int i=1;i<=Q;++i){
a[i].id=i;
opt=read();
if(opt==1){
a[i].tp=read(),a[i].T=read();
a[i].E=read();
b[++tn]=a[i].T;
}
else a[i].tp=2,a[i].T=read();
}
sort(b+1,b+tn+1);
bl=unique(b+1,b+tn+1)-b-1;
for(int i=1;i<=Q;++i){
if(a[i].tp==2){
if(!a[a[i].T].tp)
add(ice,a[a[i].T].T,-a[a[i].T].E);
else{
add(fire,a[a[i].T].T+1,-a[a[i].T].E);
E1-=a[a[i].T].E;
}
}
else{
a[i].T=lower_bound(b+1,b+bl+1,a[i].T)-b;
if(!a[i].tp)
add(ice,a[i].T,a[i].E);
else{
add(fire,a[i].T+1,a[i].E);
E1+=a[i].E;
}
}
int e0=0,e1=E1;
int f0,f1,p0,p1;
f0=f1=p0=p1=0;
for(int j=20;j>-1;--j){
int ip=p0+(1<<j);
if(ip>bl) continue;
int ie0=e0+ice[ip],ie1=e1-fire[ip];
if(ie0<ie1){
p0=ip;
e0=ie0,e1=ie1;
}
}
f0=e0;
e0=0,e1=E1;
if(p0<bl){
f1=min(ask(ice,p0+1),E1-ask(fire,p0+1));
for(int j=20;j>-1;--j){
int ip=p1+(1<<j);
if(ip>bl) continue;
int ie0=e0+ice[ip],ie1=e1-fire[ip];
if(ie0<ie1 || min(ie0,ie1)==f1){
p1=ip;
e0=ie0,e1=ie1;
}
}
}
// cerr<<E1<<" "<<e0<<" "<<e1<<" "<<f0<<" "<<f1<<" "<<p0<<" "<<p1<<endl;
if(max(f0,f1)==0) puts("Peace");
else write(f0>f1?b[p0]:b[p1]),putchar(' '),write(2*max(f0,f1)),puts("");
}
return 0;
}
P6620 [省选联考 2020 A 卷] 组合数问题
-
数学书上的 \(\sum\) be like:
\[s^2=\frac{1}{n}\sum\limits_{i=1}^n x_i^2-\overline{x}^2 \] -
\(\mathtt{OIer}\) 的 \(\sum\) be like:
\[\sum\limits_{k=0}^{n}\sum\limits_{i=0}^mb_i k^{\underline{i}}\times x^k \times \dbinom{n}{k}=\sum\limits_{i=0}^m b_i n^{\underline{i}}x^i\sum\limits_{k=0}^{n-i}\dbinom{n-i}{k-i}x^k \]这么学下去哪个 OIer 的数学不好 -
一道数论题;
-
推导过程还不是特别理解,所以先抄一下:
首先将题目中 \(f(k)\) 拆开,这样就变为多个单项式相加,每个单项式的形式都是 \(a\sum\limits_{k=1}^{n} k^p\times x^k\times\dbinom{n}{k}\)
由恒等式 \(k\times\dbinom{n}{k}=n\times\dbinom{n-1}{k-1}\) 得,\(k^p\times\dbinom{n}{k}\) 可以由它扩展到更高次幂形式得到:
下降幂:\(n^{\underline{l}}=\prod\limits_{i=n-l+1}^{n}i\)
手模后观察可知。
然后就有 \(k^p\times\dbinom{n}{k}=\sum\limits_{i=1}^p S(p,i)\times n^{\underline{i}}\times\dbinom{n-i}{k-i}\);
\(S(p,i)\) 是待定系数。但根据计算可得 \(S(p,i)=i\times S(p-1,i)+S(p-1,i-1)\)
实际上就是第二类 \(Stirling\) 数。
AC code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10+int(ch-'0');
ch=getchar();
}
return s*f;
}
#define ll long long
const int N=1005;
int n,x,p,m;
int a[N];
ll s[N][N];
ll ans=0;
ll ksm(int x,int y){
ll cnt=1,dx=x;
for(;y;y>>=1,(dx*=dx)%=p)
if(y&1)
(cnt*=dx)%=p;
return cnt;
}
int main(){
n=read(),x=read(),p=read(),m=read();
for(int i=0;i<=m;++i)
a[i]=read();
s[1][1]=1;
for(int i=2;i<=m;++i)
for(int j=1;j<=i;++j){
s[i][j]=(0ll+s[i-1][j-1]+1ll*s[i-1][j]*j%p)%p;
// cerr<<i<<" "<<j<<" "<<s[i][j]<<endl;
}
ans=(1ll*a[0]*ksm((x+1)%p,n))%p;
for(int i=1;i<=m;++i){
ll dx=(1ll*ksm(x%p,i)*ksm((1+x)%p,n-i))%p;
ll v=0;
for(int j=0;j<i;++j)
(dx*=1ll*(n-j))%=p;
for(int j=i;j<=m;++j)
(v+=1ll*s[j][i]*a[j]%p)%=p;
(ans+=1ll*v*dx%p)%=p;
// cerr<<v<<" "<<dx<<endl;
}
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号