题解 CF980D

发布时间 2023-07-17 21:53:56作者: HQJ2007

有个显然的小 trick:如果两个数相乘为平方数,那么消去平方因子后这两个数相等。

于是我们可以暴力枚举,每出现一个新数就加一,用 unordered_map 维护,然后就 T 了。

考虑优化。我们对于每个数预处理出上一个与它相等的数的位置。这样每次枚举的时候只需要看 \(pre_i\) 是否小于左边界即可。

注意特判一下 \(0\)

复杂度 \(O(n^2)\)

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5000+5;
int n,a[N],ans[N],pre[N];
int fen(int x){
  int flag=(x>=0?1:-1);
  x=abs(x);
  for(ll i=2;i*i<=x;++i){
    ll t=i*i;
    while(x%t==0)x/=t;
  }
  return x*flag;
}
int main(){
  ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
  cin>>n;
  for(int i=1;i<=n;++i){
    cin>>a[i];
    a[i]=fen(a[i]);
    for(int j=i-1;j>=1;--j){
      if(a[i]==a[j]){
        pre[i]=j;
        break;
      }
    }
  }
  for(int i=1;i<=n;++i){
    bool flag=0;
    int cnt=0;
    for(int j=i;j<=n;++j){
      if(a[j]==0)flag=1;
      if(pre[j]<i)++cnt;
      if(flag)++ans[max(cnt-1,1)];
      else ++ans[cnt];
    }
  }
  for(int i=1;i<=n;++i)cout<<ans[i]<<" ";
  cout<<endl;
  return 0;
}