[考试总结] Tham de 基本功恢复训练系列

1.12

fAKe基本功恢复训练

(来自未来的我:反正比1.15的题目要难一些)


T1 甲苯先生的滚榜

题目链接

平衡树板子题,维护两个元素

平衡树板子链接 (注释很详细)

贴个代码(Splay):

#include <bits/stdc++.h>
#define N (1000000+5)
#define DEBUG puts("!!!");
using namespace std;
typedef unsigned int ui;
ui randNum(ui &seed, ui last,const ui m){
	seed=seed*17+last;
	return seed%m+1;
}
ui m,sd,lst=7;
int t,n;
int rt,tot,fa[N],cnt[N],ch[N][2],vala[N],valb[N],siz[N];
int nowa[N],nowb[N];
inline void maintain(int x){
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];
}
inline bool get(int x){
	return x==ch[fa[x]][1];
}
inline void clear(int x){
	ch[x][0]=ch[x][1]=fa[x]=cnt[x]=vala[x]=valb[x]=siz[x]=0;
}
inline void rotate(int x){
	int y=fa[x],z=fa[y],k=get(x);
	ch[y][k]=ch[x][k^1];
	fa[ch[x][k^1]]=y;
	ch[x][k^1]=y;
	fa[y]=x;
	fa[x]=z;
	if(z) ch[z][y==ch[z][1]]=x;
	maintain(y),maintain(x);
}
inline void splay(int x,int g=0){
	while(fa[x]!=g){
		int f=fa[x],ff=fa[f];
		if(ff!=g) get(x)==get(f)?rotate(f):rotate(x);
		rotate(x);
	}
	if(!g) rt=x;
}
inline void insert(int a,int b){
	if(!rt){
		vala[++tot]=a,valb[tot]=b;
		rt=tot,cnt[tot]++;
		maintain(rt);
		return;
	}
	int cnr=rt,f=0;
	while(1){
		if(vala[cnr]==a&&valb[cnr]==b){
			cnt[cnr]++;
			maintain(cnr);
			splay(cnr);
			break;
		}
		f=cnr;
		if(a<vala[cnr]||(a==vala[cnr]&&b>valb[cnr])) cnr=ch[cnr][1];
		else cnr=ch[cnr][0];
		if(!cnr){
			vala[++tot]=a,valb[tot]=b;
			cnt[tot]++;
			fa[tot]=f,ch[f][a<vala[f]||(a==vala[f]&&b>valb[f])]=tot;
			maintain(f),maintain(tot);
了			splay(tot);
			break;
		}
	}
}
inline int rk(int a,int b){
	int res=0,cnr=rt;
	while(1){
		if(a>vala[cnr]||(a==vala[cnr]&&b<valb[cnr])) cnr=ch[cnr][0];
		else{
			res+=siz[ch[cnr][0]];
			if(a==vala[cnr]&&b==valb[cnr]){
				splay(cnr);
				return res+1;
			}
			res+=cnt[cnr];
			cnr=ch[cnr][1];
		}
	}
}
inline int pre(){
	int cnr=ch[rt][0];
	while(ch[cnr][1]) cnr=ch[cnr][1];
	return cnr;
}
inline void del(int a,int b){
	rk(a,b);
	if(cnt[rt]>1){
		cnt[rt]--,maintain(rt);
		return;
	}
	if(!ch[rt][0]&&!ch[rt][1]){
		clear(rt),rt=0;
		return;
	}
	if(!ch[rt][0]){
		int cnr=rt;
		rt=ch[cnr][1];
		fa[rt]=0;
		clear(cnr);
		return;
	}
	if(!ch[rt][1]){
		int cnr=rt;
		rt=ch[cnr][0];
		fa[rt]=0;
		clear(cnr);
		return;
	}
	int x=pre(),cnr=rt;
	splay(x);
	fa[ch[cnr][1]]=x;
	ch[x][1]=ch[cnr][1];
	clear(cnr);
	maintain(rt);
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&m,&n,&sd);
		memset(nowa,0,sizeof(nowa));//过于 chou lou
		memset(nowb,0,sizeof(nowb));
		memset(fa,0,sizeof(fa));
		memset(ch,0,sizeof(ch));
		memset(cnt,0,sizeof(cnt));
		memset(vala,0,sizeof(vala));
		memset(valb,0,sizeof(valb));
		memset(siz,0,sizeof(siz));
		rt=0,tot=0;
		while(n--){
			ui ria=randNum(sd,lst,m);
			ui rib=randNum(sd,lst,m);
			if(nowa[ria]) del(nowa[ria],nowb[ria]);
			nowa[ria]++,nowb[ria]+=rib;
			insert(nowa[ria],nowb[ria]);
			lst=rk(nowa[ria],nowb[ria])-1;
			printf("%d\n",lst);
		}
	}
	return 0;
}

T2 排列计数

题目链接

emmm 没写出来 我太菜了

主要是组合数的推导,详情请看洛谷的题解,有空我再补。。。

题解链接


T3 余数之和

题目链接

整除分块模板题

\(ans = \sum\limits_{i=1}^nk\bmod i\)

又∵ \(a\) \(\bmod\) \(b=a-b\times\lfloor{\frac{a}{b}}\rfloor\)

\(ans = \sum\limits_{i=1}^{n}{k-i \times \lfloor {\frac{k}{i}} \rfloor} = n \times k - \sum\limits_{i=1}^{n}{i \times \lfloor {\frac{k}{i}} \rfloor}\)

然后整除分块运算\(\lfloor {\frac{k}{i}} \rfloor\)

贴个代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n,k,ans;
int main(){
	scanf("%lld%lld",&n,&k);
	ans=n*k;
	for(LL l=1,r=0;l<=n;l=r+1){
		LL t=k/l;
		if(t){
			r=min(k/t,n);
		}
		else r=n;
		ans-=t*(r-l+1)*(l+r)>>1;
	}
	printf("%lld",ans);
	return 0;
}


1.15

真~基本功恢复训练

今天的题目挺水的,全部都是板子题


T1 小鸟的点心

题目链接

(SBT) 最短路板子题,使用Dijkstra,高度超过限制的点不加入队列中

果然是基本功恢复训练,搞了两个月的文化,我连Dijkstra都不记得写了 (估计我是第一个把Dijkstra里面的堆开成大根堆的)

贴个代码:

#include <bits/stdc++.h>
#define N (200000+5)
#define int long long
using namespace std;
typedef pair<int,int> paii;
int n,m,s,t,g,x;
int h[N],lim[N],dis[N],vis[N];
vector<intnanyixie> edge[N],w[N];
void add(int u,int v,int wei){
	edge[u].push_back(v);
	w[u].push_back(wei);
	edge[v].push_back(u);
	w[v].push_back(wei);
}
void dijkstra(){
	priority_queue <paii,vector<paii>,greater<paii> > q;//呜呜呜~~~
	dis[s]=0;
	int u=s;
	q.push(make_pair(0,s));
	while(!q.empty()){
		u=q.top().second;q.pop();
		vis[u]=1;
		for(int i=0;i<edge[u].size();i++){
			int now=edge[u][i];
			if(dis[now]>dis[u]+w[u][i]){
				dis[now]=dis[u]+w[u][i];
				if(!vis[now]&&(dis[now]*x+h[now]<=lim[now])){//高度超限的不加入堆
					q.push(make_pair(dis[now],now));
				}
			}
		}
	}
}
signed main(){
	freopen("oyatsu.in","r",stdin);//留着防抄
	freopen("oyatsu.out","w",stdout);
	scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&s,&t,&g,&x);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&h[i],&lim[i]);
	}
	memset(dis,0x3f,sizeof(dis));
	for(int i=1;i<=m;i++){
		int u,v,wei;
		scanf("%lld%lld%lld",&u,&v,&wei);
		add(u,v,wei);
	}
	dijkstra();
	if(dis[t]<=g) printf("%lld",dis[t]);
	else puts("wtnap wa kotori no oyatsu desu!");
	return 0;
}

T2 教主的魔法

题目链接

分块板子题,昨天才写了的

跳转链接

上代码,不解释了,要看解释的点上面的链接

#include <bits/stdc++.h>
#define N (1000000+5)
using namespace std;
int n,q,k,bl,a[N],pos[N],lazy[N],L[N],R[N];
vector <int> v[N];
void Update(int x){
	v[x].clear();
	for(int i=L[x];i<=R[x];i++){
		v[x].push_back(a[i]);
	}
	sort(v[x].begin(),v[x].end());
}
void add(int l,int r,int c){
	for(int i=l;i<=min(R[pos[l]],r);i++){
		a[i]+=c;
	}
	Update(pos[l]);
	if(pos[l]!=pos[r]){
		for(int i=L[pos[r]];i<=r;i++){
			a[i]+=c;
		}
		Update(pos[r]);
	}
	for(int i=pos[l]+1;i<pos[r];i++) lazy[i]+=c;
}
int query(int l,int r,int c){
	int x=0;
	for(int i=l;i<=min(R[pos[l]],r);i++){
		int sum=lazy[pos[l]]+a[i];
		if(sum<c) x++;
	}
	if(pos[l]!=pos[r]){
		for(int i=L[pos[r]];i<=r;i++){
			int sum=lazy[pos[l]]+a[i];
			if(sum<c) x++;
		}
	}
	for(int i=pos[l]+1;i<pos[r];i++){
		int t=c-lazy[i];
		x+=lower_bound(v[i].begin(),v[i].end(),t)-v[i].begin();
	}
	return x;
}
int main(){
	freopen("magic.in","r",stdin);//防抄
	freopen("magic.out","w",stdout);
	scanf("%d%d",&n,&q);
	k=sqrt(n),bl=n/k+(n%k!=0);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		pos[i]=(i-1)/k+1;
		v[pos[i]].push_back(a[i]);
	}
	for(int i=1;i<=bl;i++){
		L[i]=(i-1)*k+1,R[i]=i*k;
		sort(v[i].begin(),v[i].end());
	}
	R[bl]=n;
	for(int i=1;i<=q;i++){
		char opt;
		int l,r,c;
		scanf("%s",&opt);
		scanf("%d%d%d",&l,&r,&c);
		if(opt=='M') add(l,r,c);
		else if(opt=='A') printf("%d\n",r-l+1-query(l,r,c));
	}
	return 0;
}

T3 求和

题目链接

LCA板子题,先预处理每一个数的k次方,加个前缀和保证\(O(1)\)询问

其他的就不难了

估计我又是第一个把\(log_2 n\)写成\(log n\)的数学“带师”

果然我的基本功还不够扎实,不过看起来比可爱的Enterprise小姐姐好,反正都是爆零嘛~

贴一个代码,不解释了

#include <bits/stdc++.h>
#define N (300000+50)
using namespace std;
typedef long long LL;
const int mod=998244353;
int n,m,rt=1;
LL f[N][55],sum[55][N],ans;
int depth[N],fa[N][30],lgn;
vector<int> edge[N];
void add(int u,int v){
	edge[u].push_back(v);
	edge[v].push_back(u);
}
void dfs(int u,int father){
	for(int i=0;i<edge[u].size();i++){
		int now=edge[u][i];
		if(now==father) continue;
		else depth[now]=depth[u]+1,fa[now][0]=u;
		dfs(now,u);
	}
}
void getfather(){
	for(int j=1;j<=lgn;j++){
		for(int i=1;i<=n;i++){
			fa[i][j]=fa[fa[i][j-1]][j-1];
		}
	}
}
int LCA(int u,int v){
	if(depth[u]<depth[v]) swap(u,v);
	int dist=depth[u]-depth[v];
	for(int j=0;j<=lgn;j++){
		if((1<<j)&dist) u=fa[u][j];
	}
	if(u==v) return u;
	for(int j=lgn;j>=0;j--){
		if(fa[u][j]!=fa[v][j]){
			u=fa[u][j];
			v=fa[v][j];
		}
	}
	return fa[u][0];
}
void init(){
	for(int i=1;i<=300005;i++){
		for(int j=0;j<=50;j++){
			if(j==0) f[i][j]=1;
			else f[i][j]=f[i][j-1]%mod*i%mod;
		}
	}
	for(int i=1;i<=50;i++){
		for(int j=0;j<=300005;j++){
			sum[i][j]=(sum[i][j-1]+f[j][i])%mod;
		}
	}
}
int main(){
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	init();
	scanf("%d",&n);
	lgn=log2(n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	dfs(rt,0);
	getfather();
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int u,v,k;
		scanf("%d%d%d",&u,&v,&k);
		int lca=LCA(u,v);
		int du=depth[u],dv=depth[v],dl=depth[lca];
		if(lca==u){
			printf("%lld\n",(sum[k][dv]-sum[k][du-1]+mod)%mod);
		}
		else if(lca==v){
			printf("%lld\n",(sum[k][du]-sum[k][dv-1]+mod)%mod);
		}
		else printf("%lld\n",((sum[k][du]-sum[k][dl-1]+mod)%mod+(sum[k][dv]-sum[k][dl-1]+mod)%mod-f[dl][k]+mod)%mod);
	}
	return 0;
}

总结

看来还要多多训练才行啊

posted @ 2020-01-15 19:51  Xx_queue  阅读(221)  评论(4编辑  收藏  举报