Codeforces 980D

这题其实挺水的,但我比较vegetable,交了好多次才过。

题意:

给定一个序列,把这个序列的所有连续子序列分组,每组中任意两个数相乘是个完全平方数,输出每个子序列最少分的组数;

思路:

先把每个数都除去自身的完全平方因子,为什么呢?这样处理了之后,只有相同的数相乘才能变成完全平方数,而且原来相乘能变成完全平方数的数对也不会有影响,举个例子:$ 1 \times 4 = 4 $,$4$是完全平方数,除去平方因子后,变成 $1 \times 1 = 1$,$1$还是完全平方数(感性地理解YY一下就好了)

把处理完的数列从小到大排序,再离散化(防止数字太大,爆MLE)

由于题目给定n的范围是$5000$,所以不能$ O(n^3) $爆扫,QXZ大佬介绍了一种非常gin的方法,我用了离散化+桶的方法;

开个桶bo[i][j]表示1到i中数值为j的个数;然后dp,f[i][j]表示i到j的数列需要分成几个区间,f[i][j]=f[i][j-1],当第j个数在i到j中唯一时,f[i][j]++;

需要注意的点:

1、除去平方因子时要用while或者倒着扫i,防止有多个平方数;

2、排序时,要记录原来的位置,离散化完要排列回原来的序列(要按原来给定序列的子序列,而且子序列在原序列中是连续的

3、0要特判,当0为一个单独的子序列时自成一组,否则与其他任何数都能变成完全平方数(和任何数都能一组

附上蒟蒻的代码:

 

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 const int MAXN=5001;
 6 struct rec
 7 {
 8     int place,num;
 9 }a[MAXN],now;
10 bool comp1(const rec &x,const rec &y)
11 {
12     return x.num<y.num;
13 }
14 bool comp2(const rec &x,const rec &y)
15 {
16     return x.place<y.place;
17 }
18 int n,bo[MAXN][MAXN],f[MAXN][MAXN],ans[MAXN],special0;
19 bool special[MAXN];
20 main()
21 {
22     scanf("%d",&n);
23     for(int i=1;i<=n;++i)
24     {
25         scanf("%d",&a[i].num);
26         a[i].place=i;
27     }
28     for(int i=1;i<=n;++i)
29     {
30         if(a[i].num!=0)
31         {
32             int k=sqrt(abs(a[i].num));
33             for(int j=k;j>=2;--j)
34             while(a[i].num%(j*j)==0)
35             {
36                 a[i].num/=j*j;
37             }
38         } else
39         {
40             special[i]=true;
41             special0=i;
42         }
43     }
44     sort(a+1,a+n+1,comp1);
45     now.place=1;
46     now.num=a[now.place].num;
47     a[now.place].num=1;
48     for(int i=2;i<=n;++i)
49     {
50         if(a[i].num==now.num)
51         {
52             a[i].num=a[now.place].num;
53         } else
54         {
55             now.place=i;
56             now.num=a[i].num;
57             a[i].num=a[i-1].num+1;
58         }
59     }
60     sort(a+1,a+n+1,comp2);
61     for(int i=1;i<=n;++i)
62         for(int j=i;j<=n;++j)
63         bo[j][a[i].num]++;
64     special0=a[special0].num;
65     for(int i=1;i<=n;++i)
66     {
67         f[i][i]=1;
68         ++ans[f[i][i]];
69     }
70     for(int i=1;i<=n;++i)
71         for(int j=i+1;j<=n;++j)
72         {
73             f[i][j]=f[i][j-1];
74             if(bo[j][a[j].num]-bo[i-1][a[j].num]==1&&(!special[j])&&(((bo[j][special0]-bo[i-1][special0]!=j-i)||special0==0)))
75                 ++f[i][j];
76             ++ans[f[i][j]];
77         }
78     for(int i=1;i<=n;++i)
79         printf("%d ",ans[i]);
80     return 0;
81 }

 

posted @ 2018-07-25 16:02  DFSlover  阅读(333)  评论(2编辑  收藏  举报

Contact with me