​洛阳怀​​​

首先发现取前缀CSP-S 模拟 19/10/11_git的顺序一定是从后往前,然后就没有什么思路了,考虑从 CSP-S 模拟 19/10/11_i++_02 的性质入手
CSP-S 模拟 19/10/11_git_03,然后CSP-S 模拟 19/10/11_i++_04 又会取它的最小质因子
于是一个 CSP-S 模拟 19/10/11_i++_05 的所有质因子对它都有贡献,如果是好质数,有1的贡献,否则为 -1 的贡献
除掉一个 CSP-S 模拟 19/10/11_git 就是把CSP-S 模拟 19/10/11_git_07中所有数的 CSP-S 模拟 19/10/11_i++_08 给去掉,贪心判一下即可

// woj 4150
#include<bits/stdc++.h>
#define N 1000005
using namespace std;
int n,m,a[N],isp[N],prim[N],tot;
int g[N],ans;
bitset<1000000000> S;
int read(){
int cnt=0; char ch=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
void init(){
for(int i=2;i<=N-5;i++){
if(!isp[i]) isp[i]=1,prim[++tot]=i;
for(int j=1;j<=tot && prim[j]*i<=N-5;j++){
isp[i*prim[j]]=1;
if(i%prim[j]==0) break;
}
}
}
int divide(int x){
int ans=0;
for(int i=1;i<=tot && prim[i]*prim[i]<=x;i++){
while(x%prim[i]==0) ans+=S[prim[i]]?-1:1,x/=prim[i];
}
if(x>1) ans+=S[x]?-1:1;
return ans;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++) S[read()]=1;
init();
for(int i=1;i<=n;i++) ans+=divide(a[i]);
for(int i=1;i<=n;i++) g[i]=gcd(g[i-1],a[i]);
int div=1;
for(int i=n;i>=1;i--){
g[i]/=div;
int x=divide(g[i]);
if(x<0) ans+=i*(-x),div*=g[i];
}
printf("%d\n",ans);
return 0;
}

​01 串​

​ 发现 CSP-S 模拟 19/10/11_git_09于是就可以枚举每一个 CSP-S 模拟 19/10/11_i++_10
于是预处理出每一个 CSP-S 模拟 19/10/11_i++_10 向后跳的结点,然后倍增
考虑如何跟给出的 CSP-S 模拟 19/10/11_前缀和_12 串匹配,可以 CSP-S 模拟 19/10/11_前缀和_13,倍增的时候顺便处理即可

// woj 4079 
#include<bits/stdc++.h>
#define N 1000050
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
typedef unsigned long long ull;
const ull Base = 5261023;
ull S[N]; char s[N];
ull hash[N][18], pw[N];
int nxt[N][18];
int a, c, k, m, n;
ull get(int l, int r){ return S[r] - S[l-1] * pw[r - l + 1];}
int main(){
a = read(), c = read(), k = read(), m = read(), n = read();
scanf("%s", s + 1); pw[0] = 1;
for(int i = 1; i <= n; i++) pw[i] = pw[i-1] * Base, S[i] = S[i-1] * Base + s[i] - '0';
for(int i = 0; i < m; i++){
nxt[i][0] = ((1ll * i * a + c) / k) % m;
hash[i][0] = nxt[i][0] < (m/2) ? 0 : 1;
}
for(int i = 1; (1 << i) <= n; i++){
for(int j = 0; j < m; j++){
nxt[j][i] = nxt[nxt[j][i-1]][i-1];
hash[j][i] = hash[j][i-1] * pw[1 << (i-1)] + hash[nxt[j][i-1]][i-1];
}
} int ans = 0;
for(int i = 0; i < m; i++){
int pos = 1;
int x = i;
for(int j = 18; j >= 0; j--){
if(pos + (1 << j) - 1 > n) continue;
if(hash[x][j] == get(pos, pos + (1 << j) - 1)) x = nxt[x][j], pos += (1 << j);
} if(pos == n + 1) ++ ans;
} cout << ans; return 0;
}

​shop​​​

发现并没有什么数据结构支持这个操作,于是我们想到了乱搞
如果一个一个减的话,显然会CSP-S 模拟 19/10/11_i++_14,如何优化
首先当前价位最多可以买的是 CSP-S 模拟 19/10/11_git_15,但万一钱太多,就会一个一个往后跳
想到了求一个前缀和然后二分下一个跳的位置,还需要记录个数的前缀和
整理一下思路
1.我们先二分到第一个小于它的,显然要从它开始买
2.然后二分下一个点使得直接的前缀和刚好小于它
3.减去前缀和过后用 CSP-S 模拟 19/10/11_git_15处理一下当前能买的个数
4.剩下的钱递归处理
听说CSP-S 模拟 19/10/11_i++_17跳的操作类似取模,每次至少少一半,我试了下好像不是,复杂度不能严格证明
但一想到我们每次可以通过前缀和剪掉一大坨,然后将CSP-S 模拟 19/10/11_i++_17 的规模缩小到较小的 CSP-S 模拟 19/10/11_前缀和_19,我们就有信心认为我们的程序快得飞起,复杂度 CSP-S 模拟 19/10/11_前缀和_20CSP-S 模拟 19/10/11_i++_21 是递归次数,大概是 CSP-S 模拟 19/10/11_前缀和_22 级别的
所以以后一道题没有思路并不要怕,从出题人的角度看他并卡不掉你

// woj 2821
#include<bits/stdc++.h>
#define N 100050
using namespace std;
typedef long long ll;
ll read(){
ll cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
int n, m;
struct data{ int x, v;} a[N];
bool cmp(data a, data b){ return a.v > b.v;}
ll sum[N], cnt[N];
ll get(int laspos, ll w){
if(w < a[n].v) return 0;
ll ans = 0;
int l = laspos, r = n + 1;
while(l < r){
int mid = (l+r) >> 1;
if(a[mid].v <= w) r = mid;
else l = mid + 1;
}
int pos = l;
l = pos - 1; r = n;
while(l < r){
int mid = (l+r+1) >> 1;
if(sum[mid] - sum[pos-1] <= w) l = mid;
else r = mid - 1;
} int Rp = l;
laspos = Rp;
w -= sum[Rp] - sum[pos - 1];
ans += cnt[Rp] - cnt[pos - 1];
if(Rp == n) return ans;
if(Rp < n){
int k = w / a[Rp + 1].v;
w -= 1ll * k * a[Rp + 1].v; ans += k;
++laspos;
} return ans + get(laspos, w);
}
int main(){
n = read(), m = read();
for(int i = 1; i <= n; i++) a[i].v = read(), a[i].x = read();
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i++){
sum[i] = sum[i-1] + 1ll * a[i].v * a[i].x;
cnt[i] = cnt[i-1] + (ll)a[i].x;
}
while(m--){
ll w = read();
cout << get(1, w) << '\n';
} return 0;
}