题目链接: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 ",ans); return 0; }