1. 程式人生 > >Codeforces Round #104 (Div. 1) D Lucky Pair

Codeforces Round #104 (Div. 1) D Lucky Pair

題目連結:Lucky Pair
題意:只含有 4 和 7 的數字為幸運數字,給一個長度為 n 的序列,問有多少對互不相交的子區間,滿足兩個區間中沒有相同的幸運數字。
題解:大致做法比較容易想,但是細節有點多有點雜,幾乎是在別人題解幫助下完成的。所有區間組合的個數為C(n,4)+2×C(n,3)+C(n,2),然後計算不合法的區間對數。最多隻有 1000 個幸運數字,列舉第二個區間所包含的最左邊的幸運數字 i,接著列舉第二個區間最右邊的幸運數字 j,找到在第二個區間前面相同的幸運數字的位置 pos,找到在 set 中的 pos 前後位置 L、R,並把 pos 存入 set 中,不合法情況便是第一個區間包含 pos 不包含 L 和 R。分情況討論第一個區間右端點和第二個區間左端點之間是否有幸運數字進行計算。

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long LL;

LL n,cnt,ans,tot;
LL a[100005],pos[100005],pre[100005];

LL C(LL x,LL y){
    if(y==2) return x*(x-1)/2;
    if(y==3) return x*(x-1)/2*(x-2)/3;
    if(y==4) return (x-3)*(x-2)/2*(x-1)/3*x/4;
}

bool islucky(LL x){
    while(x){
        
if(x%10!=4&&x%10!=7) return false; x/=10; } return true; } int main(){ scanf("%lld",&n); pos[0]=0; ans=C(n,4)+C(n,3)*2+C(n,2); for(LL i=1;i<=n;i++){ scanf("%d",&a[i]); if(islucky(a[i])){ pos[++cnt]=i; for
(LL j=1;j<cnt;j++){ if(a[pos[j]]==a[pos[cnt]]) pre[cnt]=j; } } } pos[cnt+1]=n+1; for(LL i=2;i<=cnt;i++){ set<LL> s; s.insert(0); LL temp=0; for(LL j=i;j<=cnt;j++){ if(pre[j]<i){ LL k=pre[j]; while(k){ set<LL>::iterator L,R; L=R=s.lower_bound(pos[k]); L--; if(R!=s.end()){ temp+=(pos[k]-(*L)) * ((*R)-pos[k]) * (pos[i]-pos[i-1]); } else{ temp+=(pos[k]-(*L)) * (pos[i-1]-pos[k]) * (pos[i]-pos[i-1]); temp+=(pos[k]-(*L)) * C(pos[i]-pos[i-1]+1,2); } s.insert(pos[k]); k=pre[k]; } } ans-=temp*(pos[j+1]-pos[j]); } } printf("%lld\n",ans); return 0; }