Codeforces1783(EDU141)E. Game of the Year-数论、取整函数、前缀和
题目:https://codeforces.com/problemset/problem/1783/E
题目大概是说两个人在打boss,名字太长了就叫A和B好了,A和B轮流打,每个人每次打k下boss,如果A打满了a[i]下或者B打满b[i]下就把boss秒了…现在一共有n关,现在问你哪些k(从1取到n),可以让A在每关都能把boss秒了(K头是吧)
题解:
(不知道这题为什么有2300分的…)
因为A先手,所以肯定是在\(\lceil \frac{a_i}{k}\rceil\)次攻击的时候A才能打死boss,需要B在此之前没有打死boss,所以\((\lceil \frac{a_i}{k}\rceil-1)*k<b_i\)
考虑反面情况,A能把所有boss都打死,反过来就是存在一个boss被B打死,即存在某个i使得\((\lceil \frac{a_i}{k}\rceil-1)*k>=b_i\),即\(\lceil \frac{a_i}{k}\rceil>\lceil \frac{b_i}{k}\rceil\)
这意味着存在某个\(x\)在\([\lceil\frac{b_i}{k}\rceil,\lceil\frac{a_i}{k}\rceil)\)内,化简过来即\(b_i\leq xk<a_i\)
所以只要先枚举k,再枚举k的倍数j,check一下j是否位于某一个\([b_i,a_i)\)内即可,前缀和预处理一下就可以\(O(1)\)实现这个check
注:如果是从另一个角度考虑除法分块的话,好像会TLE
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
using namespace std;
const int N=2e5+5;
int n,a[N],b[N],tag[N];
vector<int> ans;
int main(){
fastio;
int T;cin>>T;
while(T--){
cin>>n;
rep(i,1,n)cin>>a[i];
rep(i,1,n)cin>>b[i];
rep(i,1,n)tag[i]=0;
ans.clear();
rep(i,1,n)if(a[i]>b[i])tag[b[i]]++,tag[a[i]]--;
rep(i,1,n)tag[i]+=tag[i-1];
rep(k,1,n){
bool ok=1;
for(int j=k;j<=n;j+=k)if(tag[j])ok=0;
if(ok)ans.push_back(k);
}
cout<<ans.size()<<endl;
for(auto x:ans)cout<<x<<' ';cout<<endl;
}
return 0;
}