codeforces 895/B sort+二分
In first sample there are only three suitable pairs of indexes — (1, 2), (2, 3), (3, 4).
In second sample there are four suitable pairs of indexes(1, 1), (2, 2), (3, 3), (4, 4).
In third sample every pair (i, j) is suitable, so the answer is 5 * 5 = 25.
題目大致的意思是說給你n個數
ai ....aj
其中1<=i<=j<=n
然後有一個x 和k 你要尋找所有的序列 使得
這個序列中的從第一個元素到最後一個元素(包括這兩個)之間恰好有k個可以被x整除
看用例第一個用例就是讓我們找到所有的序列滿足他們之間最多被2整除的數有一個
那麼1,3 3,5 5,7 是這樣的唯一三組數 對應的下標為(1, 2), (2, 3), (3, 4)
那如果是 (1,3)呢 這樣的話 1,2,3,4,5 中間2,4都可以被2整除 就不滿足只有一個的情況了。
最後要你輸出的是所有這樣的序列數之和。
解題思路:
可以看出,如果打亂原序列是不會改變所得結果的個數的,其實這個證明起來也不難,但是我覺得沒有必要把時間浪費在這裡
當時就這麼做了,其實也是懷著猜的心態,但是後來感覺還好。因為他說(i,j) 和(j,i)不是一對的, 所以如果你(i,j)原來是滿足的話
那麼如果排序後打亂順序,他們在的位置是(i2,j2) 或者(j2,i2)一定有且唯一有一個滿足條件。具體的話有興趣的可以自己嘗試一下,
重點是sort之後可以用二分 可以縮短時間複雜度,故想到排序這樣。
那麼我們對這組數進行排序之後 開始用二分查詢,怎麼查詢呢?
我分了幾類討論,在程式碼中有註釋,如果想自己再試下我先說個思路
被 x整數的有k個 那麼對於 第a[i]的數來說 可以允許的數大約是k*x+a[i附近(當然要考慮餘數的情況)
可以允許最大的數確定了之後允許的最小的數也就確定 max-(x-1) 就是
比如你是要被5整數 你現在是1 然後 只允許有一個 所以是 5-9 都可以 10 就又可以被整除了 不能要
而如果是4的話 一個都沒有 也不可以
照著這個思路程式如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node
{
ll num,val;
};
node a[100005];
bool cmp(const node&a,const node &b)
{
if(a.val!=b.val) return a.val<b.val;
else return a.num<b.num;
}
//兩種二分方式
inline ll bis1(ll,ll);
inline ll bis2(ll,ll);
//key1 key2 分別代表當前數允許的最小值和最大值
ll n,x,k,key1,key2;
int main()
{
scanf("%lld%lld%lld",&n,&x,&k);
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i].val);
a[i].num=i+1;
}
sort(a,a+n,cmp);
ll ans=0;
ll len;
ll l,r;
for(int i=0;i<n;i++)
{
//分了四類情況
//第一類是當前數整除但是隻有0個整數 直接continue
//第二類是當前數整除 k不等於0 修正key1
//第三類是k==0 修正key2
if(a[i].val%x==0&&k==0) continue;
else if(a[i].val%x==0&&k!=0)
{
key1=a[i].val+x*(k-1);
key2=key1+x-1;
}
else if(a[i].val%x!=0&&k==0)
{
key1=a[i].val;
key2=key1+x-1-a[i].val%x;
}
else
{
key1=a[i].val+k*x-a[i].val%x;
key2=key1+x-1;
}
//考慮兩種情況 一種是查最小的時候 要優先選左側的 查最大的優先右側
//就是改變等號歸哪邊的事
l=bis1(0,n-1);
r=bis2(0,n-1);
if(a[r].val>=key1)
ans+=r-l+1;
}
printf("%lld\n",ans);
return 0;
}
inline ll bis1(ll l,ll r)
{
if(r<=l+1)
{
if(a[l].val>=key1) return l;
else return r;
}
ll mid=(l+r)/2;
if(key1<a[mid].val) bis1(mid,r);
else bis1(l,mid);
}
inline ll bis2(ll l,ll r)
{
if(r<=l+1)
{
if(a[r].val<=key2) return r;
else return l;
}
ll mid=(l+r)/2;
if(key2>=a[mid].val) bis2(mid,r);
else bis2(l,mid);
}
我承認有點麻煩..不過最後一A還是很開心的啊hh