桃花村 题解(思维+数学)
题目链接
题目思路
这个题目真的挺有意思的
任意取一个坐标设他的\(A_i\)为\(a\)和\(abs(i-x)\)为\(dis\)
则显然若在\(h\)时刻的燃烧程度为\(t\)则要满足
\(a\times (h-dis)=t\)
则显然\(t\)为\(a\)的倍数
而你如果知道t可以枚举\(a\),那么你也知道\(h\),则\(dis\)值你也知道
把所有\(t\)相同的操作储存起来,最后一起操作
顺便注意\(t=0\)的情况要特判
代码是借鉴rank前几的很简单
复杂度就是一个调和级数
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,m,x;
int a[maxn];
int opt[maxn],h[maxn],t[maxn];
int ans[maxn];
unordered_map<int,int> mp[maxn];
vector<pair<int,int> > vec[maxn];
int num[maxn];
signed main(){
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
int dis=abs(i-x);
num[dis]++;
mp[dis][a[i]]++;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&opt[i],&h[i]);
if(opt[i]==1){
scanf("%d",&t[i]);
vec[t[i]].push_back({i,h[i]});
}
}
for(int i=1;i<=1e6;i++){
for(int j=i;j<=1e6;j+=i){//枚举t[i]
int a=j/i;
for(auto k:vec[j]){
int dis=k.se-a;
if(dis<0) continue;
if(mp[dis].count(i)){
ans[k.fi]+=mp[dis][i];
}
}
}
}
ll pr=0;
for(int i=1;i<=m;i++){
if(opt[i]==1){
if(t[i]==0){
pr+=num[h[i]];
}else{
pr+=ans[i];
}
}else{
printf("%lld\n",pr);
}
}
return 0;
}
不摆烂了,写题