2021.11.5考试总结[冲刺NOIP模拟23]

T1 回文

转化成从 \((1,1)\)\((n,m)\) 同时开始走,坐标 \(DP\)

走的步数奇偶不同,统计答案的方式略有不同。

\(code:\)

T1
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	#define fi first
	#define se second
	#define pb push_back
	#define mpr make_pair
	typedef double DB; typedef long double LD;
	typedef long long LL; typedef unsigned long long ULL;
	typedef pair<int,int>PII;
	int read(){
		LL x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(LL x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(LL& x,LL y){ x=x>y?x:y; }
} using namespace IO;
const int NN=510,mod=993244853;
int n,m,ext,ans,mat[NN][NN];
int f[2][NN][NN];
char ch[NN];

signed main(){
	freopen("palin.in","r",stdin);
	freopen("palin.out","w",stdout);
	n=read(); m=read(); ext=(n+m-2)>>1;
	for(int i=1;i<=n;i++){
		scanf("%s",ch+1);
		for(int j=1;j<=m;j++) mat[i][j]=ch[j]-'a';
	}
	if(mat[1][1]!=mat[n][m]){ puts("0"); exit(0); }
	f[0][1][n]=1;
	for(int i=0;i<ext;i++){
		int lmx=min(n,i+1),lmy=max(1,n-i);
		memset(f[i+1&1],0,sizeof(f[i+1&1]));
		for(int j=1;j<=lmx;j++){
			int x=i-j+2;
			for(int k=n;k>=lmy;k--){
				int y=n+m-k-i;
				if(x<m&&y>1) if(mat[j][x+1]==mat[k][y-1]) (f[i+1&1][j][k]+=f[i&1][j][k])%=mod;
				if(x<m&&k>1) if(mat[j][x+1]==mat[k-1][y]) (f[i+1&1][j][k-1]+=f[i&1][j][k])%=mod;
				if(j<n&&y>1) if(mat[j+1][x]==mat[k][y-1]) (f[i+1&1][j+1][k]+=f[i&1][j][k])%=mod;
				if(j<n&&k>1) if(mat[j+1][x]==mat[k-1][y]) (f[i+1&1][j+1][k-1]+=f[i&1][j][k])%=mod;
			}
		}
	}
	for(int i=1;i<=n;i++){
		(ans+=f[ext&1][i][i])%=mod;
		if((n+m&1)&&i<n) (ans+=f[ext&1][i][i+1])%=mod;
	}
	write(ans,'\n');
	return 0;
}

T2 快速排序

分析给出的代码,找出排序的本质。

从左往右扫描,遇到 nan 直接填到答案中,遇到数 \(x\) 则找到它之后所有未计入答案的数,排序后计入答案。

排个序,单调指针。

\(code:\)

T2
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef double DB; typedef long double LD;
	typedef long long LL; typedef unsigned long long ULL;
	int read(){
		LL x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(LL x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(LL& x,LL y){ x=x>y?x:y; }
} using namespace IO;

const int NN=500010;
int t,n,mx,now,nows;
vector<int>sot;

namespace Number_IO{
	struct number{
		bool is;
		int v;
		number(){ is=1; v=0; }
		number(int x){ is=0; v=x; }
	}num[NN],ans[NN];
	number Read(){
		int x=0,it=0; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='n'){ getchar(); getchar(); return number(); } ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return number(x);
	}
	void Write(number x,char sp){
		char ch[20]; int len=0,v=x.v;
		if(x.is){ putchar('n'); putchar('a'); putchar('n'); putchar(sp); return; }
		do{ ch[len++]=v%10+'0'; v/=10; }while(v);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
} using namespace Number_IO;

signed main(){
	freopen("qsort.in","r",stdin);
	freopen("qsort.out","w",stdout);
	t=read();
	while(t--){
		n=read(); mx=now=nows=0;
		sot.clear();
		for(int i=1;i<=n;i++){
			num[i]=Read();
			if(!num[i].is) sot.push_back(num[i].v);
		}
		sort(sot.begin(),sot.end());
		for(int i=1;i<=n;i++)
			if(num[i].is) ans[++now]=num[i];
			else if(num[i].v<mx) continue;
			else{
				while(sot[nows]<num[i].v) ans[++now]=number(sot[nows++]);
				ans[++now]=sot[nows++]; mx=num[i].v;
			}
		for(int i=1;i<=n;i++) Write(ans[i],i==n?'\n':' ');
	}
	return 0;
}

T3 混乱邪恶

构造方案:先 \(-1\)\(1\) 交替,之后将排序后的 \(a_{2i}\)\(a_{2i-1}\) 分为一组并作差,将差值从大到小扫描,通过交换同一组元素的答案来调整两边的和。

证明一定有解:

证明正确性: link

\(code:\)

T3
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	#define fi first
	#define se second
	#define pb push_back
	#define mpr make_pair
	typedef double DB; typedef long double LD;
	typedef long long LL; typedef unsigned long long ULL;
	typedef pair<int,int>PII;
	int read(){
		LL x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(LL x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(LL& x,LL y){ x=x>y?x:y; }
} using namespace IO;

const int NN=1000010;
int n,m,sum,ans[NN];
vector<int>vec[NN];
struct Data{
	int id,vl;
	bool operator<(const Data& tmp)const{
		return vl<tmp.vl;
	}
}a[NN];

signed main(){
	freopen("chaoticevil.in","r",stdin);
	freopen("chaoticevil.out","w",stdout);
	n=read(); m=read();
	for(int i=1;i<=n;i++) a[i].id=i,a[i].vl=read();
	puts("NP-Hard solved");
	sort(a+1,a+n+1);
	for(int i=1+(n&1);i<=n;i+=2){
		sum+=a[i+1].vl-a[i].vl;
		vec[a[i+1].vl-a[i].vl].push_back(i);
		ans[a[i+1].id]=1; ans[a[i].id]=-1;
	}
	if(n&1) sum-=a[1].vl,ans[a[1].id]=-1;
	for(int i=m;i;i--) if(vec[i].size()&&sum>=2*i)
		for(int x:vec[i]){
			sum-=2*i;
			swap(ans[a[x].id],ans[a[x+1].id]);
			if(sum<2*i) break;
		}
	for(int i=1;i<=n;i++) write(ans[i],' ');
	return puts(""),0;
}

T4 校门外歪脖子树上的鸽子

将每次修改抽象成一条链,第一个断开链的点将这个区间分为两段,左边一段是树上靠左区间的一段后缀,对链上所有点的右儿子有贡献,同理,右边一段对所有左儿子有贡献。

于是树剖,将一个点的贡献存在它的兄弟上,每次找到链的位置进行修改或查询。

边界恶心的离谱。

\(code:\)

T4
#include<bits/stdc++.h>
#define int long long
using namespace std;																																																																																																																			namespace IO{ int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } void write(int x,char sp){ char ch[20]; int len=0; if(x<0) x=-x,putchar('-'); do{ ch[len++]=x%10+'0'; x/=10; }while(x); for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); } } using namespace IO;

const int NN=400010;
int n,m,ext,root,L[NN],R[NN],sn[NN][2],fa[NN],len[NN],lp[NN],rp[NN];
map<int,int>mp[NN];
bool pos(int x){ return x==sn[fa[x]][1]; }
int bro(int x){ return x==root?root:sn[fa[x]][pos(x)^1]; }
void dfs(int s){
	L[s]=R[s]=s;
	if(sn[s][0]) dfs(sn[s][0]),L[s]=L[sn[s][0]];
	if(sn[s][1]) dfs(sn[s][1]),R[s]=R[sn[s][1]];
	if(L[s]>R[s]) swap(sn[s][0],sn[s][1]),L[s]=L[sn[s][0]],R[s]=R[sn[s][1]];
	len[s]=R[s]-L[s]+1; mp[L[s]][R[s]]=s;
}

namespace Tree_Chain{
	int cnt,id[NN],dep[NN],dfn[NN],siz[NN],son[NN],top[NN];
	void dfs1(int s){
		dep[s]=dep[fa[s]]+1; siz[s]=1;
		if(s==root) lp[s]=rp[s]=s;
		else{
			lp[s]=pos(s)?s:lp[fa[s]];
			rp[s]=pos(s)?rp[fa[s]]:s;
		}
		if(sn[s][0]) dfs1(sn[s][0]),siz[s]+=siz[sn[s][0]];
		if(sn[s][1]) dfs1(sn[s][1]),siz[s]+=siz[sn[s][1]];
		son[s]=siz[sn[s][0]]>siz[sn[s][1]]?sn[s][0]:sn[s][1];
	}
	void dfs2(int s,int t){
		dfn[s]=++cnt; id[cnt]=s; top[s]=t;
		if(!son[s]) return;
		dfs2(son[s],t);
		(son[s]==sn[s][0])?dfs2(sn[s][1],sn[s][1]):dfs2(sn[s][0],sn[s][0]);
	}
	int LCA(int x,int y){
		while(top[x]!=top[y]) dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
		return dep[x]<dep[y]?x:y;
	}
	int rtson(int x,int y){
		x=top[x];
		while(x!=top[y])
			if(fa[x]==y) return x;
			else x=top[fa[x]];
		return son[y];
	}
} using namespace Tree_Chain;

namespace Segment_Tree{
	#define ld rt<<1
	#define rd (rt<<1)|1
	struct segment_tree{
		int w[NN<<2],tag[NN<<2],sum[NN<<2];
		void pushup(int rt){ sum[rt]=sum[ld]+sum[rd]; }
		void down(int rt,int val){ sum[rt]+=val*w[rt]; tag[rt]+=val; }
		void pushdown(int rt){ if(tag[rt]) down(ld,tag[rt]),down(rd,tag[rt]),tag[rt]=0; }
		void build(int rt,int l,int r,int typ){
			if(l==r){ w[rt]=(pos(bro(id[l]))!=typ)?len[bro(id[l])]:0; return; }
			int mid=l+r>>1;
			build(ld,l,mid,typ); build(rd,mid+1,r,typ);
			w[rt]=w[ld]+w[rd];
		}
		void update(int rt,int l,int r,int opl,int opr,int val){
			if(l>=opl&&r<=opr) return down(rt,val),void();
			pushdown(rt);
			int mid=l+r>>1;
			if(opl<=mid) update(ld,l,mid,opl,opr,val);
			if(opr>mid) update(rd,mid+1,r,opl,opr,val);
			pushup(rt);
		}
		int query(int rt,int l,int r,int opl,int opr){
			if(l>=opl&&r<=opr) return sum[rt];
			pushdown(rt);
			int mid=l+r>>1,res=0;
			if(opl<=mid) res+=query(ld,l,mid,opl,opr);
			if(opr>mid) res+=query(rd,mid+1,r,opl,opr);
			return res;
		}
		void UPD(int x,int y,int val){
			while(top[x]!=top[y]) update(1,1,ext,dfn[top[x]],dfn[x],val),x=fa[top[x]];
			if(x!=y) update(1,1,ext,dfn[y]+1,dfn[x],val);
		}
		int ASK(int x,int y,int res=0){
			while(top[x]!=top[y]) res+=query(1,1,ext,dfn[top[x]],dfn[x]),x=fa[top[x]];
			if(x!=y) res+=query(1,1,ext,dfn[y]+1,dfn[x]);
			return res;
		}
	}ls,rs;
} using namespace Segment_Tree;

void single_upd(int x,int v){
	if(pos(x)) ls.update(1,1,ext,dfn[bro(x)],dfn[bro(x)],v);
	else rs.update(1,1,ext,dfn[bro(x)],dfn[bro(x)],v);
}
int single_ask(int x){
	if(pos(x)) return ls.query(1,1,ext,dfn[bro(x)],dfn[bro(x)]);
	return rs.query(1,1,ext,dfn[bro(x)],dfn[bro(x)]);
}

signed main(){
	freopen("pigeons.in","r",stdin);
	freopen("pigeons.out","w",stdout);
	n=read(); m=read(); ext=2*n-1;
	for(int i=1;i<n;i++){
		sn[n+i][0]=read(); fa[sn[n+i][0]]=n+i;
		sn[n+i][1]=read(); fa[sn[n+i][1]]=n+i;
	}
	for(int i=1;i<n;i++) if(!fa[n+i]) root=n+i;
	dfs(root); dfs1(root); dfs2(root,root);
	ls.build(1,1,ext,0); rs.build(1,1,ext,1);
	while(m--){
		int op=read(),x=read(),y=read(),qd,lca=LCA(x,y);
		if(op==1){
			qd=read();
			if(mp[x].find(y)!=mp[x].end()){ single_upd(mp[x][y],qd); continue; }
			int xx=lp[x],yy=rp[y];
			if(dep[xx]<=dep[lca]) single_upd(rtson(x,lca),qd);
			else single_upd(xx,qd), ls.UPD(xx,rtson(x,lca),qd);
			if(dep[yy]<=dep[lca]) single_upd(rtson(y,lca),qd);
			else single_upd(yy,qd), rs.UPD(yy,rtson(y,lca),qd);
		} else{
			if(mp[x].find(y)!=mp[x].end()){ write(single_ask(mp[x][y]),'\n'); continue; }
			int xx=lp[x],yy=rp[y],res=0;
			if(dep[xx]<=dep[lca]) res+=single_ask(rtson(x,lca));
			else res+=single_ask(xx)+ls.ASK(xx,rtson(x,lca));
			if(dep[yy]<=dep[lca]) res+=single_ask(rtson(y,lca));
			else res+=single_ask(yy)+rs.ASK(yy,rtson(y,lca));
			write(res,'\n');
		}
	}
	return 0;
}
posted @ 2021-11-05 20:44  keen_z  阅读(74)  评论(0编辑  收藏  举报