分组
题目描述
小 C 在了解了她所需要的信息之后,让兔子们调整到了恰当的位置。小 C 准备给兔子 们分成若干个小组来喂恰当的胡萝卜给兔子们吃。
此时, nnn 只兔子按一定顺序排成一排,第 iii 只兔子的颜色是 aia_iai 。由于顺序已经是被 调整好了的,所以每个小组都应当是序列上连续的一段。
在分组前,小 C 发现了一个规律:有些兔子会两两发生矛盾。并且,两只兔子会发生矛 盾,当且仅当代表他们的颜色的数值之和为一个正整数的平方。比如,1 色兔子和 2 色兔子 不会发生矛盾,因为 3 不是任何一个正整数的平方;而 1 色兔子却会和 3 色兔子发生矛盾, 因为 4=224 = 2^24=22。
小 C 认为,只要一个小组内的矛盾不要过大就行。因此,小 C 定义了一个小组的矛盾 值 kkk ,表示在这个小组里,至少需要将这个组再一次分成 kkk 个小团体;每个小团体并不需 要是序列上连续的一段,但是需要使得每个小团体内任意两只兔子之间都不会发生矛盾。
小 C 要求,矛盾值最大的小组的矛盾值 kkk 不超过 KKK 就可以了。当然,这样的分组方 法可能会有很多个;为了使得分组变得更加和谐,小 C 想知道,在保证分组数量最少的情况 下,字典序最小的方案是什么。你能帮帮她吗?
字典序最小的方案是指,按顺序排列分组的间隔位置,即所有存在兔子 iii 和 i+1i + 1i+1 在 不同组的位置 iii,和其它所有相同分组组数相同的可行方案相比总有第一个不同的位置比其 它方案小的方案。
输入输出格式
输入格式:
从标准输入中读入数据。
输入第 1 行两个正整数 n,Kn,Kn,K。
输入第 2 行 nnn 个正整数,第 iii 个数表示第 iii 只兔子的颜色 aia_iai。
输出格式:
输出到标准输出中。
输出第 1 行一个正整数 mmm,为你至少需要将兔子分为多少个小组。
输出第 2 行m−1m-1m−1个从小到大的排列的正整数,第 iii 个数 sis_isi 表示 sis_isi 和 si+1s_i + 1si+1 在 你的方案里被分到了两个小组。如果 m=1m = 1m=1,那么请输出一个空行。
输入输出样例
说明
【样例 1 解释】
如果将五只兔子全部分到同一个小组的话,那么 (1, 3) (3, 6) (6, 10) (10, 15) (1, 15) 均 不能分到同一个小团体;因为最多分成两个小团体,所以为了满足前 4 对限制,只能分为 {{1, 6, 15}, {3, 10}},但此时不满足 (1, 15) ,所以不存在一种组数为 1 的方案满足全部限制。
如果将五只兔子分为两个小组的话,一种字典序最小的可行的分组方案是 {1}, {3, 15, 10, 6},此时第二组内的小团体数量不超过 2 的一种分法是 {{3, 10}, {15, 6}}。
【数据范围】
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解 决一部分测试数据。
每个测试点的数据规模及特点如下表:
特殊性质 1:保证最优分组方案唯一。
特殊性质 2:保证不会有两只相同颜色的兔子。
从后向前选,能多选就多选,
理由:数字越少肯定越优,同时间隔尽量向前推,字典序尽量小
当k=1时很简单,直接走一边,每次枚举1~512判断,看是否存在x^2-a[i]的值
当k=2时,每一组可以分两组,那么要出现i无法分配的情况
那只能是a[i]+a[j]=x^2,a[i]+a[k]=y^2 a[j]+a[k]=z^2
即j和k不能分一起,i也不能放在j或k在的一组
于是用镜像并查集
如果满足条件,那么i和j不能放一起,于是可以理解为i+n和j不可以放一起,i和j+n不可以放一起
如果出现了如上情况,那么就会出现i和k+n,k都不能放一起,也就是i和k属同一个集合
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 int set[400001],p[1001],a[400001],vis[400001],cnt,n,k; 8 vector<int>map[400001]; 9 vector<int>v; 10 vector<int>ans; 11 int find(int x) 12 { 13 if (set[x]!=x) set[x]=find(set[x]); 14 return set[x]; 15 } 16 bool pd(int x,int y) 17 { 18 if (find(x)==find(y)) return 1; 19 return 0; 20 } 21 void add(int x,int y) 22 { 23 int p=find(x),q=find(y); 24 if (p!=q) 25 set[p]=q; 26 } 27 bool check1(int x) 28 {int i; 29 for (i=512;i>=1;i--) 30 if (p[i]<=a[x]) return 1; 31 else 32 { 33 if (vis[p[i]-a[x]]&&vis[p[i]-a[x]]==cnt) 34 return 0; 35 } 36 return 1; 37 } 38 bool check2(int x) 39 {int i,j; 40 for (i=512;i>=1;i--) 41 if (p[i]<=a[x]) return 1; 42 else 43 { 44 if (vis[p[i]-a[x]]&&vis[p[i]-a[x]]==cnt) 45 { 46 for (j=0;j<map[p[i]-a[x]].size();j++) 47 { 48 if (pd(x,map[p[i]-a[x]][j])) 49 return 0; 50 add(x,map[p[i]-a[x]][j]+n); 51 add(x+n,map[p[i]-a[x]][j]); 52 } 53 } 54 } 55 return 1; 56 } 57 void solve1() 58 {int i; 59 cnt=1; 60 for (i=1;i<=512;i++) 61 p[i]=i*i; 62 for (i=1;i<=n;i++) 63 scanf("%d",&a[i]); 64 for (i=n;i>=1;i--) 65 if (check1(i)) 66 { 67 vis[a[i]]=cnt; 68 } 69 else 70 { 71 cnt++; 72 vis[a[i]]=cnt; 73 v.push_back(i); 74 } 75 cout<<cnt<<endl; 76 for (i=v.size()-1;i>=0;i--) 77 printf("%d ",v[i]); 78 } 79 void solve2() 80 {int i; 81 cnt=1; 82 for (i=1;i<=512;i++) 83 p[i]=i*i; 84 for (i=1;i<=n;i++) 85 scanf("%d",&a[i]); 86 for (i=1;i<=2*n;i++) 87 set[i]=i; 88 for (i=n;i>=1;i--) 89 if (check2(i)) 90 { 91 if (vis[a[i]]!=cnt) 92 vis[a[i]]=cnt,map[a[i]].clear(); 93 map[a[i]].push_back(i); 94 } 95 else 96 { 97 cnt++; 98 vis[a[i]]=cnt; 99 map[a[i]].clear(); 100 map[a[i]].push_back(i); 101 ans.push_back(i); 102 } 103 cout<<cnt<<endl; 104 for (i=ans.size()-1;i>=0;i--) 105 printf("%d ",ans[i]); 106 } 107 int main() 108 { 109 cin>>n>>k; 110 if (k==1) 111 solve1(); 112 else solve2(); 113 }