9.22

9.22

(1)区间——正解:差分,my:线段树乱搞

我的想法,每次找到最小的点以及其位置,然后把这个点减到0,然后递归左右区间,显然“最小的点以及其位置”可用线段树维护,复杂度O(nlogn)

正解:

将原数组差分,每次操作相当于在一个左边的位置 +1 同时在一个右边 的位置-1,暴力扫描一遍即可

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
#define MP make_pair
using namespace std;
const int N=1e7+5;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,val[N];
int mi[N],a[N],pos[N];
inline void pushup(int p) {
	if(mi[p]>=mi[ls]) mi[p]=mi[ls],pos[p]=pos[ls];
	if(mi[p]>=mi[rs]) mi[p]=mi[rs],pos[p]=pos[rs];
}
void build(int l,int r,int p) {
	if(l==r) {
		mi[p]=a[l];pos[p]=l;
		return;
	}
	build(l,mid,ls);
	build(mid+1,r,rs);
	pushup(p);
}
int cnt;
pair<int,int>ans[N];
pair<int,int> query(int l,int r,int L,int R,int p) {
	if(L>r||l>R) return MP(0x3f3f3f3f,0x3f3f3f3f);
	if(L<=l&&r<=R) return MP(mi[p],pos[p]);
	if(R<=mid) return query(l,mid,L,R,ls);
	else if(L>mid) return query(mid+1,r,L,R,rs);
	else {
		pair<int,int> f1=query(l,mid,L,R,ls),f2=query(mid+1,r,L,R,rs);
		if(f1.first<f2.first) return f1;
		else return f2;
	}
}
void dfs(int l,int r,int pre) {
	if(l>r) return;
	pair<int,int> now=query(1,n,l,r,1);
 	for(int i=1;i<=now.first-pre;i++)
		ans[++cnt]=MP(l,r);
	if(now.second==l&&l==r) return;
	dfs(l,now.second-1,now.first);
	dfs(now.second+1,r,now.first);
}
int main() {
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	memset(mi,0x3f,sizeof(mi));
	build(1,n,1);
	dfs(1,n,0);
	printf("%d\n",cnt);
	for(int i=1;i<=cnt;i++)
		printf("%d %d\n",ans[i].first,ans[i].second);
	return 0;
}


正解:

积木大赛其实是一样的,再输出个方案数就行

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=1e5+5;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,a[N],st[N],tp,f[N];
int main() {
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int pre=a[1],now=0;
	for(int i=2;i<=n;i++) {
		if(a[i]<=a[i-1]) now=pre;
		else now=pre+a[i]-a[i-1];
		pre=now;
	}
	printf("%d\n",now);
	for(int i=1;i<=n;i++) {
		if(a[i]>a[i-1]) {
			for(int j=1;j<=a[i]-a[i-1];j++)
				st[++tp]=i;
		}
		if(a[i]>a[i+1]) {
			for(int j=1;j<=a[i]-a[i+1];j++)
				printf("%d %d\n",st[tp--],i);
		}
	}
	return 0;
}


相似的题目

IncDec Sequence

参考这个https://www.cnblogs.com/Leohh/p/7655155.html

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=100005;
typedef long long ll;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,a[N];
ll jue(ll x){return x>0?x:(-x);}
int main() {
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	ll pos=0,neg=0;
	for(int i=2;i<=n;i++)
		if(a[i]>a[i-1]) pos+=a[i]-a[i-1];
		else neg+=a[i-1]-a[i];
	printf("%lld\n%lld\n",max(pos,neg),jue(pos-neg)+1);
	return 0;
}

(2)计数+容斥/背包

45分快乐暴力

#include <cstdio>
#include <vector>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=105;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,m,cnt;
long long ans;
int p[N],a[N];
int main() {
	n=read();m=read();p[0]=0;
	if(m==0) {
		printf("0");return 0;
	} 
	for(int i=1;i<=n;i++)
		if(n%i==0) {
			++p[0];p[p[0]]=i;
		}
	if(m==1) {
		for(int i=1;i<=p[0];i++)
			for(int j=1;j<=p[0];j++)
				if(p[i]*p[j]<=n)
					ans++;
		printf("%d\n",ans);
		return 0;
	}
	if(m==2) {
		int mx=n*n;
		for(int i1=1;i1<=p[0];i1++)
			for(int i2=1;i2<=p[0];i2++)
				for(int i3=1;i3<=p[0];i3++)
					for(int i4=1;i4<=p[0];i4++)
						if(p[i1]*p[i2]*p[i3]*p[i4]<=mx)
							ans++;
		printf("%d\n",ans%998244353);return 0;
	}
	if(m==3) {
		int mx=n*n*n;
		for(int i1=1;i1<=p[0];i1++) {
			for(int i2=1;i2<=p[0];i2++) {
				if(p[i1]*p[i2]>mx) break;
				for(int i3=1;i3<=p[0];i3++) {
					if(p[i1]*p[i2]*p[i3]>mx) break;
					for(int i4=1;i4<=p[0];i4++) {
						if(p[i1]*p[i2]*p[i3]*p[i4]>mx) break;
						for(int i5=1;i5<=p[0];i5++) {
							if(p[i1]*p[i2]*p[i3]*p[i4]*p[i5]>mx) break;
							for(int i6=1;i6<=p[0];i6++)
								if(p[i1]*p[i2]*p[i3]*p[i4]*p[i5]*p[i6]<=mx)ans++;
								else break;								
						}
					}
				}
			}
		}

		printf("%d\n",ans%998244353);return 0;
	}
	return 0;
}


接着solution

然后最后那个背包可以转化成容斥

\[质因数分解\\ \prod_{i=1}^{2m} x[i]^{k[i]}=n^m\\ 设t[i]是n的因数p[i]分解后的指数\\ 我们要找\sum_{i=1}^{2m}t[i]=m*k[1]~(t[i]<=k[1])\\ 然后问题转化成了2m个盒子,放m*k - i * (k + 1),有i个大于等于(k+1)的t[],隔板法可以为空, \]

#include <iostream>
#include <cassert>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
const int MAXN=5005;
const int P=998244353;
int n,m,ans,ans1,ans2=1,fac[MAXN],inv[MAXN];
inline int read() {
	int x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
	return x;
}
int qpow(int x,int b) {
	long long res=1,a=x%P;//注意要化成统一类型 
	while(b){
		if(b&1) res=res*a%P;
		a=a*a%P;
		b>>=1;
	}
	return res;
}
inline int get() {
	int sum=0;
	for (int i=1;i*i<=n;i++) {
		if(n%i) continue;
		sum++,sum+=(i*i!=n);
	}
	return sum%P;
}//num_factor 
inline int C(int x,int y) {
	if(x<0||y<0||y>x) return 0;
	return 1ll*fac[x]*inv[y]%P*inv[x-y]%P;
}
inline int calc(int k) {//容斥 
	int sum=0;
	for (int i=0;i<=m;i++)
		if(i&1) sum+=P-1ll*C(m*2,i)*C(k*m-i*(k+1)+m*2-1,m*2-1)%P,sum%=P; 
		else sum+=1ll*C(m*2,i)*C(k*m-i*(k+1)+m*2-1,m*2-1)%P,sum%=P;
	return sum;
}
int main() {
	n=read(),m=read();
	ans1=qpow(get(),m*2);
	fac[0]=1;
	for (int i=1;i<=5000;i++)
		fac[i]=1ll*fac[i-1]*i%P;
	inv[5000]=qpow(fac[5000],P-2);
	for (int i=5000;i;i--)
		inv[i-1]=1ll*inv[i]*i%P;
	for (int i=2;i*i<=n;i++) {
		int tot=0;
		if(n%i) continue;
		while(n%i==0) tot++,n/=i;
		ans2=1ll*ans2*calc(tot)%P;
	}//get_factor 
	if(n!=1) ans2=1ll*ans2*calc(1)%P;
	printf("%lld\n",1ll*(ans1+ans2)*qpow(2,P-2)%P);
	return 0;
}

(3)train——正解:并查集 My:树剖

自闭了——审题错误。。。以为只把m里 的经过的打标记——实际上是路径上的所有点都要打标记,线段树区间加95分不翼而飞

实际100分只需搞成树状数组就好

树状数组优点是跑的飞快(写的简单),缺点就是占空间大

总体复杂度是O(nlogn^2)——树剖log+树状数组不到Log

#include <queue>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=500005;
const int M=1000005;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
inline void Max(int &x,int y){if(x<y)x=y;}
inline void Min(int &x,int y){if(x>y)x=y;}
int n,m;
int hd[N],nxt[M],to[M],tot;
inline void add(int x,int y) {
	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
}

int fa[N],dep[N],son[N],siz[N];
void dfs_son(int x,int f) {
	fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(y==f) continue;
		dfs_son(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]]) son[x]=y;
	}
}
int top[N],dfn[N],rev[N],dfn_cnt;
void dfs_chain(int x,int tp) {
	top[x]=tp;
	dfn[x]=++dfn_cnt;rev[dfn_cnt]=x;
	if(son[x]) dfs_chain(son[x],tp);
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(y==son[x]||y==fa[x]) continue;
		dfs_chain(y,y);
	}
}
int dist(int x,int y) {
	int res=dep[x]+dep[y];
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	int lca=dep[x]<dep[y]?x:y;
	return res-2*dep[lca];
}

int t[N*2];
void upd(int x,int k) {	for(;x<=n;x+=x&(-x))t[x]+=k;}
int query(int x) {int ans=0;for(;x;x-=x&(-x))ans+=t[x];return ans;}

void modify(int x,int y,int z) { 
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		upd(dfn[top[x]],z);upd(dfn[x]+1,-z);//区间修改 
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	upd(dfn[x],z);upd(dfn[y]+1,-z);
}
int st;
bool vis[N];
long long ans;
int main() {
//	freopen("3.in","r",stdin);
//	freopen("3.out","w",stdout);
	n=read();m=read();st=read();
	for(int i=1,x,y;i<n;i++) {
		x=read();y=read();
		add(x,y);add(y,x);
	}
	dfs_son(1,0);
	dfs_chain(1,1);
	for(int i=1,x;i<=m;i++) {
		x=read();
		//query(dfn[x])单点查询 
		if(query(dfn[x])) continue;	
		modify(st,x,1);
		ans+=dist(st,x);
		st=x;
	}
	printf("%lld\n",ans);
	return 0;
}


当然了正解其实更妙

并查集维护——我们要把x——y上的点都标记,然后我们可以拆成两条链,一条x——lca,一条y——lca,然后暴力跳find跳fa,这样的话我们把路径上的fa[x]都改成了fa[lca],然后每次查询时如果find(x)!=x则说明其被标记过,直接continue

这样我们发现每个点都是只被经过一次,加上并查集复杂度O(logn),总共O(nlogn)

#include <queue>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=500005;
const int M=1000005;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,m;
int hd[N],nxt[M],to[M],tot;
inline void add(int x,int y) {
	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
}

int fa[N],dep[N],son[N],siz[N];
void dfs_son(int x,int f) {
	fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(y==f) continue;
		dfs_son(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]]) son[x]=y;
	}
}
int top[N],dfn[N],rev[N],dfn_cnt;
void dfs_chain(int x,int tp) {
	top[x]=tp;
	dfn[x]=++dfn_cnt;rev[dfn_cnt]=x;
	if(son[x]) dfs_chain(son[x],tp);
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(y==son[x]||y==fa[x]) continue;
		dfs_chain(y,y);
	}
}
int LCA(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}

int st;
long long ans;
int f[N];
inline int find(int x) {
	return x==f[x]?x:f[x]=find(f[x]);
}
int main() {
//	freopen("3.in","r",stdin);
//	freopen("3.out","w",stdout);
	n=read();m=read();st=read();
	for(int i=1,x,y;i<n;i++) {
		x=read();y=read();
		add(x,y);add(y,x);
	}
	dfs_son(1,0);
	dfs_chain(1,1);
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1,x;i<=m;i++) {
		x=read();
		if(find(x)!=x) continue;
		int lca=LCA(x,st);
		ans+=dep[x]+dep[st]-2*dep[lca];
		int fx=find(x),fy=find(st);
		while(dep[fx]>=dep[lca]) 
			f[fx]=fa[fx],fx=find(fx);
		while(dep[fy]>=dep[lca]) 
			f[fy]=fa[fy],fy=find(fy);
		st=x;
	}
	printf("%lld\n",ans);
	return 0;
}


posted @ 2020-10-08 16:54  ke_xin  阅读(43)  评论(0编辑  收藏  举报