其他分享
首页 > 其他分享> > 2022杭电多校第八场1、7、5

2022杭电多校第八场1、7、5

作者:互联网

1001 Theramore

观察以下两种情况:

以0为例,上图就是说,只要有两个连续的0,我们就可以一直把它们往前移动直到移动到首位。同理只要有两个连续的1我们就可以把它们移动到尾部。

所以可以开一个栈,顺序将字符入栈,一旦遇到连续的0或者1,就把它们删去,在首尾打下标记。

const int N=1e5+5;
int T;
char stk[N],s[N];
int top;

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%s",s+1);
		int n=strlen(s+1);
		int hh=0,tt=0;
		top=0;
		for(int i=1;i<=n;i++){
			if(!top)stk[++top]=s[i];
			else{
				while(stk[top]==s[i]){
					if(s[i]=='1')tt+=2;
					if(s[i]=='0')hh+=2;
					top--; i++;
				}
				if(i<=n)stk[++top]=s[i];
			}
		}
		
		for(int i=1;i<=hh;i++)printf("%c",'0');
		for(int i=1;i<=top;i++)printf("%c",stk[i]);
		for(int i=1;i<=tt;i++)printf("%c",'1');
		printf("\n");
	}
	return 0;
}

1007 Darnassus

如果把\(|i−j|∗|pi−pj|\)看作边权,题目就是要求最小生成树,但是两两之间建边数量太多了,考虑如何优化这一过程。

可以发现,如果我们选择\((1,2),(2,3),(3,4)....\)这些边,最后边长一定不会超过\(n-1\),所以最小生成树的边长也都不会超过\(n-1\)。因此\(|i−j|∗|pi−pj|\)的其中一部分必然小于等于\(\sqrt{n}\),我们可以枚举这部分边,时间复杂度是\(O(n\sqrt{n})\)。

我们不能对边排序,因为时间复杂度超了,考虑用链表记录每个边权对应的所有边。

(然后加了快读和并查集按秩合并还是超时了qwq我真没办法了)

const int N=5e4+5,M=N*sqrt(N);
typedef long long ll;
int T;
int n,dx;
int p[N],id[N];
int f[N],rk[N];
int top;
int h[N],idx;
int fr[M],e[M],ne[M];

inline int findx(int x){
	if(f[x]!=x)return f[x]=findx(f[x]);
	else return x;
}

inline void merge(int u,int v){
	if(rk[u]<=rk[v])f[u]=v;
	else f[v]=u;
	if(rk[u]==rk[v])rk[v]++;
}

inline void adde(int u,int v,int val){
	fr[idx]=u; e[idx]=v; ne[idx]=h[val]; h[val]=idx++; 
}

inline 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*10+ch-'0',ch=getchar();
    return x*f;
}

inline void write(ll x)
{
    if(x<0)
        putchar('-'),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
    return;
}

int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;i++){
			p[i]=read();
			id[p[i]]=i;
			h[i]=-1;
		}
		dx=sqrt(n);
		
		idx=0;
		for(int i=1;i<=n;i++){
			for(int j=i+1;j<=min(n,i+dx);j++){
				int c1=abs(i-j)*abs(p[i]-p[j]);
				int c2=abs(i-j)*abs(id[i]-id[j]);
				if(c1<=n-1)adde(i,j,c1);
				if(c2<=n-1)adde(id[i],id[j],c2);
			}
		}
		
		for(int i=1;i<=n;i++){ f[i]=i; rk[i]=1;}
		
		ll res=0;
		int cnt=0;
		for(int i=1;i<=n-1;i++){
			for(int j=h[i];~j;j=ne[j]){
				int u=fr[j],v=e[j];
				u=findx(u); v=findx(v);
				if(u!=v){
					merge(u,v);
					res+=i;
					cnt++;
					if(cnt>=n-1)break;
				}
			}
			if(cnt>=n-1)break;
		}
		write(res);puts("");
	}
	return 0;
}

1005 Ironforge

std被hack了,听说题目假了。

但是还是有可以学习的地方。关键词:并查集、预处理最小质因子、二分判断一列递增的数中是否存在区间[l,r]中的点。

代码参考:ygg2022 杭电多校(8) 个人题解 更新至7题 - 知乎 (zhihu.com)

const int N=2e5+5;
int T,n,m;
int a[N],b[N];
int l[N],r[N];
int st[N],primes[N],cnt,mp[N];
vector<int>pos[N];

void min_prime(int k){
	for (int i = 2; i <= 200000; i++) {
	    if (mp[i])continue;
	    for (int j = i; j <= 200000; j += i) {
	        if (mp[j] == 0)mp[j] = i;
	    }
	}
}

void Prime_decom(){
	for(int i=1;i<=n;i++){
		int x=a[i];
		while(x>1){
			int p=mp[x];
			while(x%p==0)x/=p;
			pos[p].push_back(i);
		}
	}
}

bool pass(int p,int l,int r){
	if(pos[p].size()==0)return 0;
	else return upper_bound(pos[p].begin(),pos[p].end(),r)-
				lower_bound(pos[p].begin(),pos[p].end(),l);
}

int main(){
	min_prime(N-5);
	scanf("%d",&T);
	while(T--){
		for(int i=1;i<=N-5;i++)pos[i].clear();
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		for(int i=1;i<n;i++)scanf("%d",&b[i]);
		
		Prime_decom();
		
		for(int i=n;i>=1;i--){
			r[i]=i;
			while(r[i]<n && pass(b[r[i]],i,r[i]))r[i]=r[r[i]+1];
		}
		
		for(int i=1;i<=n;i++){
			l[i]=i;
			
			if(i>1 && r[i-1]>=i){
				if(pass(b[i-1],i,r[i])){
					r[i]=r[i-1];
					l[i]=l[i-1];
				}
			}
			else{
				while(1){
					int flag=0;
					while(l[i]>1 && pass(b[l[i]-1],l[i],r[i])){
						l[i]=l[l[i]-1];
                    	flag=1;
					}
					while(r[i]<n && pass(b[r[i]],l[i],r[i])){
						r[i]=r[r[i]+1];
						flag=1;
					}
					if(!flag)break;
				}
			}
		}
		
		int x,y;
		for(int i=1;i<=m;i++){
			scanf("%d%d",&x,&y);
			if(l[x]<=y && r[x]>=y)cout<<"Yes"<<endl;
			else cout<<"No"<<endl;
		}
	}
	return (0-0);
}

标签:杭电多校,return,int,第八,pos,--,while,2022,const
来源: https://www.cnblogs.com/tshaaa/p/16589538.html