标签:mem names 表示 ext src click signed 不同的 mes
一个很简单的数学题,简单推一下就好,路丽姐姐教你学数学。
将式子化出我们发现只需求出$i\times i/n$的个数
那么我们将$n$质因数分解,可知因子个数
为了整除$n$,令$i==\sqrt{n\times k} $,我们需要让$k$含有$n$中奇数个数的因子
然后同时还可以有其他的平方因子,直接爆求即可。
思路积累:
1.对于求$i\times i/n$可以从$n$的因子上下手
一个$DP$的大神题,考场被各种剪枝cao过
$ \%\%\%\%\%kx,Duanyue $线段树$AC$
$n^2$DP显然不说了
正解:
首先记清几个数组的定义:
$pre_{i}$表示当前遍历情况下权值为$i$的点的最近出现的位置
$pos_{j}$表示当前从$pos_{j}+1$到$i$之间不同的数字小于等于$j$的位置
$cnt_{j}$表示当前从$pos_{j}+1$到$i$之间不同的数字个数
然后分析题意,因为最坏情况下,我们分$n$段权值为$n$
所以对于每段的数字个数我们不能取过$\sqrt{n}$;
那么我们考虑转移:
但我们添加一个新的数时
假如他的$pre_{a_{i}}$大于当前枚举的$pos_{j}$,那么$a_{i}$已经不是第一次出现了
所以对$cnt_{j}$没有贡献
但是假如小于等于的话....显然此时$cnt_{j}++$可能大于$j$,所以此时$pos_{j}$要移动
那么在移动时我们要让$cnt_{j}--$,所以我们应该找到第一个$pre_{a_{pos_{j}}}$等于$pos_{j}$的
因为这样意味着我们将$pos_{j}$移到此处时,正好减去了一个元素,使元素不在$pos_{j}+1$到$i$出现
复杂度证明:
每个指针即每个$j$有$\sqrt{n}$个且最多移动$n$次。
#include<bits/stdc++.h> #define MAXN 41000 using namespace std; int read(){ int x=0;char c=getchar();int ff=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)ff=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*ff; } int pre[MAXN],cnt[MAXN],pos[MAXN],f[MAXN];int n,m; int a[MAXN]; signed main(){ memset(f,0x3f3f3f,sizeof(f)); f[0]=0; n=read();m=read(); for(int i=1;i<=n;++i)a[i]=read(); for(int i=1;i<=n;++i){ for(int j=1;j<=sqrt(n);++j){ //printf("pre[%d]=%d\n",a[i],pre[a[i]]); if(pre[a[i]]<=pos[j]){ cnt[j]++; if(cnt[j]>j){ pos[j]++; while(pre[a[pos[j]]]>pos[j]){ pos[j]++; } cnt[j]=j; } } f[i]=min(f[pos[j]]+cnt[j]*cnt[j],f[i]); //printf("f[%d]=%d pos[%d]=%d\n",i,f[i],j,pos[j]); } pre[a[i]]=i; } printf("%d\n",f[n]); }
思路积累
1.考场能减的枝一定要减,万一A了呢.....
2.对于题意性质转化,因为有很多区间的值的贡献是一样的,因为题中答案是$cnt^2$,考虑枚举$\sqrt{n}$的值
标签:mem names 表示 ext src click signed 不同的 mes
原文地址:https://www.cnblogs.com/Wwb123/p/11664069.html