正题
这题很显然吧,给出幸运数字个数<=1000就是要你用一个平方级别的复杂度来完成。
我们枚举必须包含的一个幸运数字区间,然后将包含的幸运数字全部涂黑,那么就可以很快的计算答案了。
对于一个不包含幸运数字的,可以直接计算答案。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
#include<vector>
using namespace std;
const int N=100010;
int dis[1010],next[N];
long long sum[N];
set<int> S;
int n,tot,t;
int a[N];
vector<int> pos[1010];
bool tf[1010];
map<int ,int> mp;
set<int>::iterator it;
int X,Y;
bool check(int x){
int op=x;
while(x){
if(x%10!=4 && x%10!=7) return false;
x/=10;
}
if(!mp[op]) mp[op]=++tot;
return true;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(check(a[i])) pos[mp[a[i]]].push_back(i),dis[++t]=i;
}
for(int i=1;i<=n;i++) sum[i]=1ll*i*(i+1)/2,sum[i]+=sum[i-1];
long long ans=0,tot,p;dis[t+1]=n+1;
int now=1;
for(int i=1;i<=n;i++){
if(check(a[i])) now++;
else ans+=1ll*(dis[now]-i)*(1ll*(i-1)*i/2);
}
for(int i=1;i<=t;i++){
S.clear();S.insert(0);
p=0;memset(tf,false,sizeof(tf));
for(int j=i;j<=t;j++){
int id=mp[a[dis[j]]];
if(!tf[id]){
tf[id]=true;
for(int k=0;k<pos[id].size();k++){
if(pos[id][k]>=dis[i]) break;
it=S.lower_bound(pos[id][k]);
if(it==S.end()){
it--;X=*it;
p+=1ll*(pos[id][k]-X-1)*(pos[id][k]-X)/2;
}
else{
Y=*it;it--;X=*it;
p-=1ll*(Y-X-1)*(Y-X)/2;
p+=1ll*(Y-pos[id][k]-1)*(Y-pos[id][k])/2;
p+=1ll*(pos[id][k]-X-1)*(pos[id][k]-X)/2;
}
S.insert(pos[id][k]);
}
}
it=S.end();it--;X=*it;
tot=1ll*(dis[i]-dis[i-1])*p+sum[dis[i]-X-1]-sum[dis[i-1]-X-1];
tot*=dis[j+1]-dis[j];
ans+=tot;
}
}
printf("%lld\n",ans);
}
本文深入探讨了一种针对幸运数字的区间算法,通过枚举必须包含的幸运数字区间,快速计算出不含幸运数字的区间的答案,利用平方级别的复杂度解决特定问题。
819

被折叠的 条评论
为什么被折叠?



