zoukankan      html  css  js  c++  java
  • [考试总结] 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
    ",lst);
    		}
    	}
    	return 0;
    }
    

    T2 排列计数

    题目链接

    emmm 没写出来 我太菜了

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

    题解链接


    T3 余数之和

    题目链接

    整除分块模板题

    (ans = sumlimits_{i=1}^nkmod i)

    又∵ (a) (mod) (b=a-b imeslfloor{frac{a}{b}} floor)

    (ans = sumlimits_{i=1}^{n}{k-i imes lfloor {frac{k}{i}} floor} = n imes k - sumlimits_{i=1}^{n}{i imes lfloor {frac{k}{i}} floor})

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

    贴个代码:

    #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
    ",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
    ",(sum[k][dv]-sum[k][du-1]+mod)%mod);
    		}
    		else if(lca==v){
    			printf("%lld
    ",(sum[k][du]-sum[k][dv-1]+mod)%mod);
    		}
    		else printf("%lld
    ",((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;
    }
    

    总结

    看来还要多多训练才行啊

    转载请注明出处--Xx_queue
  • 相关阅读:
    《统计学习方法》
    《赤裸裸的统计学》
    a[i]=i++
    正态分布(normal distribution)
    可视化
    数据转换
    beLazy
    水到渠成
    数据过滤
    数据合并
  • 原文地址:https://www.cnblogs.com/Xx-queue/p/12198479.html
Copyright © 2011-2022 走看看