• 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
    ",cnt);
    	for(int i=1;i<=cnt;i++)
    		printf("%d %d
    ",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
    ",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
    ",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
    %lld
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",ans);
    	return 0;
    }
    
    
    

  • 相关阅读:
    Spring5.2.x04BeanDefinitionMap
    spring配置类解析
    spring5 解析配置类
    分布式唯一id生成器
    电脑变流畅的方法(也是网吧电脑比家里的电脑流畅的原因)
    nginx启动访问
    Win10按f5不能刷新页面 变成了调节亮度怎么办?
    Linux 内核定时器
    Linux 中断下半部工作队列(work queue)
    Linux 虚拟字符设备globalmem
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13781879.html
Copyright © 2020-2023  润新知