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

article6/8/2023 12:02:06 AM/文章来源:https://www.cnblogs.com/tshaaa/p/16589538.html

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)

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

using namespace std;

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{
		int x=lower_bound(pos[p].begin(),pos[p].end(),l)-pos[p].begin();
		if(x<pos[p].size() && r>=pos[p][x])return 1;
		else return 0;
	}
	return 1;
}

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],l[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])){
                   	 	if (i <= r[l[i] - 1]) {
                        	r[i]=r[l[i] - 1];
                        	l[i]=l[l[i] - 1];
                        	break;
                    	}
                    	flag=1;
                    	l[i]=l[l[i]-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);
			//cout<<l[x]<<' '<<r[x]<<endl;
			if(l[x]<=y && r[x]>=y)cout<<"Yes"<<endl;
			else cout<<"No"<<endl;
		}
	}
	return (0-0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.wtld.cn/a/70.html

如若内容造成侵权/违法违规/事实不符,请联系方塘网进行投诉反馈,一经查实,立即删除!

相关文章

Bert bert-base-uncased 模型加载

1、下载模型相关文件到本地路径 https://huggingface.co/bert-base-uncased/tree/main2、修改模型加载,注释为修改前

A层省选4

场均一题放弃 A. 我 我切题了 发现图上有环可以不停的转,让空位到我们需要的地方去,而环的具体形态并不重要,我们只需要知道环的大小(\(size\))和环内元素个数(\(cnt\))即可 所以使用\(tarjan\)缩点,然后转化为一个\(DAG\)上的问题 发现环的大小等于元素个数时,我们必须先…

fa

\[ax+by\equiv X_i \]$$\texttt{--END--}$$我的博客: $\texttt{1Liu}$ 本文链接: https://www.cnblogs.com/OLiuO/p/16589553.html 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!