1. 程式人生 > >JZOJ 4307. 【NOIP2015模擬11.3晚】喝喝喝

JZOJ 4307. 【NOIP2015模擬11.3晚】喝喝喝

JZOJ 4307. 【NOIP2015模擬11.3晚】喝喝喝

題目

Description

在這裡插入圖片描述

Input

在這裡插入圖片描述

Output

在這裡插入圖片描述

Sample Input

3 2
5 3 1

Sample Output

4

Data Constraint

在這裡插入圖片描述

題解

首先看一條顯而易見的性質,若滿足 x m o

d    y = k x \mod y=k ,則 y
x k y|x-k
,且 y > k y>k

為了求答案方便,每次迴圈到 i i 時,加上以 i i 結尾的滿足條件子陣列的個數。
怎麼求?
我們不難發現,假設當前以 i i 結尾的滿足條件子陣列的開頭最小可到 x x ,則以 i + 1 i+1 結尾的滿足條件子陣列的開頭最小隻能到 x x ,否則其中必包含“壞對”。
則我們設一個指標 l a s t last ,表示當前滿足條件子陣列的開頭最小為 l a s t last l a s t last 是滿足遞增的。
考慮如何將 l a s t last 後移。
找到 a [ i ] a[i] 前最後一個 a [ l ] a[l] 滿足 ( a [ l ] , a [ i ] ) (a[l],a[i]) 是一個壞對,也就是 a [ i ] a [ l ] k a[i]|a[l]-k
f [ i ] = l f[i]=l ,表示 i a [ l ] k i|a[l]-k ,且沒有滿足條件的更小的 l l ,也就是最後一個滿足 i a [ l ] k i|a[l]-k l l
更新 l a s t last 時,判斷 f [ a [ i ] ] f[a[i]] l a s t last 的大小關係,取較大值。
更新 f f 陣列時,用 a [ i ] \sqrt{a[i]} 的時間,將所有的 f [ j ] = i f[j]=i j a [ i ] k j|a[i]-k )。
又有一個問題, ( 2 , 5 ) (2,5) 也是一個“壞對”,也就是 a [ x ] = k a[x]=k ,但用這種方法判斷不出。
所以再用一個變數維護最後一個出現 a [ l ] = k a[l]=k 的位置。

程式碼

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int f[100010],a[100010];
int main()
{
	int n,k,i,j,last=0,p=0;
	long long ans=0;
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	for(i=1;i<=n;i++)
	{
		if(a[i]>k&&f[a[i]]>last) last=f[a[i]];
		
		if(a[i]>k&&p>last) last=p;
		ans+=i-last;
		int t=a[i]-k;
		if(a[i]==k) p=i;
		for(j=1;j<=floor(sqrt(t));j++) if(t%j==0) f[j]=f[t/j]=i;
	}
	printf("%lld",ans);
	return 0;
}