【IOI周赛-普及组】桃花村
桃花村
https://ac.nowcoder.com/acm/contest/11231/D
题解讲的非常清楚,写个题解加深一下自己的印象
对原题抽象、建模后,对于每个的操作其实就是若干个一次函数,求满足的i的数量。
等式变完形后就是,显然对于该的操作,会爆炸的村庄需要满足以下两个条件:
1.
2.
所以大致思路就是枚举的因子,确定,然后判断距离为的村庄是否等于
接着处理几个细节,用调和级数预处理出的倍数,建立一颗数指向所有因子的森林,在枚举因子时可以。
时需要特判,因为没有存0的因子
相同的村庄只有两个,桶排一下。
MyCode:
#include <bits/stdc++.h> using namespace std; const int maxn=1e6+7,maxm=1e6*25,mod=1e9+7; typedef long long int ll; typedef unsigned long long ull; int head[maxn],Next[maxm],to[maxm],tot,n,m,x,a[maxn][2]; inline void add(int x,int y) { to[++tot]=y; Next[tot]=head[x]; head[x]=tot; } inline void preint() { for(int i=1; i<=1000000; ++i) for(int j=i; j<=1000000; j+=i) add(j,i); for(int i=1,y,j; i<=n; ++i) { cin>>y; if(a[j=abs(i-x)][0]) a[j][1]=y; else a[j][0]=y; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n>>m>>x; preint(); int op,h,t,ans(0); while(m--) { cin>>op>>h; if(op&1) { cin>>t; if(!t) { if(!h) { ans+=1; continue; } if(x+h<=n) ans+=1; if(x-h>=1) ans+=1; continue; } for(int i=head[t],y=to[i],dis; i; i=Next[i],y=to[i]) { dis=h-t/y; if(dis<0) continue; if(a[dis][0]==y) ans+=1; if(a[dis][1]==y) ans+=1; } } else { cout<<ans<<'\n'; cout.flush(); } } return 0; }