zoukankan      html  css  js  c++  java
  • 【题解】洛谷 P3940 划分【20201014 CSP 模拟赛】【贪心 带权并查集】

    题目链接

    题目链接

    题意

    将序列 \(s\) 分为尽可能少、断点字典序尽可能小的段,要求每一段都能通过被分为 \(k\) 个集合,使每个集合内部没有两个数之和为完全平方数。\(n,s_i\leq 2^{18}\)\(k\in \{1,2\}\)

    题解

    从后往前贪心显然最优,只需要判断一个段再加一个数之后是否仍能分成 \(k\) 个集合即可。\(k=1\) 是 trivial 的(用桶之类的维护即可),\(k=2\) 时就是判断是否是二分图,这个拿带权并查集维护即可。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    ll getint(){
    	ll ans=0,f=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-')f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		ans=ans*10+c-'0';
    		c=getchar();
    	}
    	return ans*f;
    }
    const int N=1.5e5+10;
    int n,k,a[N];
    int v;
    
    namespace subt_k1{
    
    int b[N];
    
    }
    
    
    namespace subt_k2{
    
    vector<int>b[N];
    int f[N],d[N];
    int _(int x){
    	if(x==f[x])return x;
    	int t=_(f[x]);
    	d[x]+=d[f[x]];
    	f[x]=t;
    	return f[x];
    }
    int merge(int x,int y){
    	int xx=_(x),yy=_(y);
    	f[yy]=xx;
    	d[yy]=d[x]+d[y]+1;
    }
    
    }
    
    vector<int>ans;
    
    int main(){
    	n=getint(),k=getint();
    	for(int i=1;i<=n;i++)v=max(v,a[i]=getint());
    	if(k==1){
    		using namespace subt_k1;
    		int r=n;
    		for(int i=n;i>=1;--i){
    			bool ok=1;
    			for(int j=1;j*j-a[i]<=v;j++){
    				if(j*j-a[i]>=0&&b[j*j-a[i]]){
    					ok=0;
    					break;
    				}
    			}
    			if(!ok){
    				ans.push_back(i);
    				for(int j=i+1;j<=r;j++)b[a[j]]=0;
    				r=i;
    			}
    			b[a[i]]=1;
    		}
    	}else{
    		using namespace subt_k2;
    		for(int i=1;i<=n;i++)f[i]=i;
    		int r=n;
    		for(int i=n;i>=1;--i){
    			bool ok=1;
    			if(b[a[i]].size()>2)continue;
    			for(int j=1;j*j-a[i]<=v;j++){
    				if(j*j-a[i]>=0){
    					for(auto x:b[j*j-a[i]]){
    						int y=i;
    						int xx=_(x),yy=_(y);
    						if(xx!=yy){
    							merge(x,y);
    							continue;
    						}
    						if((d[x]+d[y])%2)continue;
    						ok=0;
    						break;
    					}
    				}
    			}
    			if(!ok){
    				ans.push_back(i);
    				for(int j=i;j<=r;j++)b[a[j]].clear(),d[j]=0,f[j]=j;
    				r=i;
    			}
    			b[a[i]].push_back(i);
    		}
    	}
    	printf("%d\n",ans.size()+1);
    	for(int i=ans.size()-1;i>=0;i--){
    		printf("%d ",ans[i]);
    	}
    	return 0;
    }
    
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    Django drf 功能组件
    Django drf 视图家族
    Django drf初级
    Django drf序列化器 Serializer
    VUE 全整理
    Django Xadmin的安装方式
    python virtualenv虚拟环境搭建
    版本控制器:操作流程
    版本控制器:GIT线上操作
    《剑指offer》---跳台阶问题
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/13813105.html
Copyright © 2011-2022 走看看