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;
}
posted @ 2023-03-25 14:00  Star_LIcsAy  阅读(82)  评论(0)    收藏  举报