题意:
非常纠结的题意。
其实是把这n个数分成若干个长度任意的连续区间。
对于每个区间,取一个数,如果这个区间里剩下的数中没有一个数是这个数的约数。
那么说明这个数可取。
问你对于所有的区间,一共能取多少个数。
思路:
类似的计算方式。
比如 5 4 1 2 3 这5个数
看成
5
5 4
4
5 4 1
4 1
1
5 4 1 (2)
4 1 (2)
1 (2)
2
...
先过一遍保证后面的数不能是前面的数的倍数。
这么遍历的时候其实就是看当前这个数的约数是否在前面的数中出现过(sqrt(ai)的复杂度)
然后把这个数放上去,顺便标记。
就比如第四个数2,本来可以放4次,但是由于1在其前面距离1的位置,所有3个都不能放了,只能放一个。
然后这样的会出现一个情况,就是放的数是之前数的约数。
这样的话就从右往左再过一遍。
把放的次数给减掉。
比如对于4
他距离1有一个单位的距离,放4的时候放了2个,那么其实就是多放了1到末尾这么多次的2个。
减掉就好了。
所有最后的复杂度是(2*n*sqrt(n))。
代码:
#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"cmath"
#include"map"
#include"vector"
#include"string"
using namespace std;
#define ll __int64
ll mod=1000000000+7;
int v[123456],mp[12345];
int kx[123456];
int main()
{
int n;
while(scanf("%d",&n)!=-1)
{
memset(mp,0,sizeof(mp));
for(int i=1; i<=n; i++) scanf("%d",&v[i]);
ll ans=0,sum=0;
for(int i=1; i<=n; i++)
{
int tep=0,lit=sqrt(v[i]*1.0);
for(int j=1; j<=lit; j++)
{
if(v[i]%j==0)
{
tep=max(tep,mp[j]);
tep=max(tep,mp[v[i]/j]);
}
}
sum=sum+((i-tep))%mod;
kx[i]=i-tep;
ans=(ans+sum)%mod;
mp[v[i]]=i;
// printf("%I64d %I64d\n",sum,ans);
}
for(int i=0; i<=10000; i++) mp[i]=n+1;
sum=0;
for(int i=n; i>=1; i--)
{
int tep=n+1,lit=sqrt(v[i]*1.0);
for(int j=1; j<=lit; j++)
{
if(v[i]%j==0)
{
tep=min(tep,mp[j]);
tep=min(tep,mp[v[i]/j]);
}
}
if(tep!=n+1)
sum=(sum+kx[i]*(n+1-tep))%mod;
mp[v[i]]=i;
}
printf("%I64d\n",((ans-sum)%mod+mod)%mod);
}
return 0;
}