test20190924 老L
80+50+100=230。T1没做出来说明我数列学得不好?
LOLO 的含树
现有函数
给出 \(n,m\),求 \(g_m(n) \bmod (10^9+7)\)。
\(0 \leq m < n \leq 10^9\)。
HDU6680 Rikka with Quicksort
令 \(a_n=g_m(n),s_n=\sum_{i=1}^na_i\),则原式在 \(n>m\) 时可以写作
对 \(s_n\) 进行处理
两边同时除以 \((n+1)(n+2)\) 得到
令 \(f_n=\frac{s_n}{(n+1)(n+2)}\),那么原式可以写成
分块打表预处理 \(\frac{n-1}{(n+1)(n+2)}\) 前缀和即可。
这个打表程序还是有点技术含量的,暴力打表特别慢。时间复杂度 \(O(L \log P)\)。
co int N=4e8+3; int f[N]; il int inv(int x){ if(x<N) return f[x]; if(x%2==0) return mul(f[2],inv(x/2)); if(x%3==0) return mul(f[3],inv(x/3)); if(x%5==0) return mul(f[5],inv(x/5)); if(x%7==0) return mul(f[7],inv(x/7)); if(x%11==0) return mul(f[11],inv(x/11)); if(x%13==0) return mul(f[13],inv(x/13)); if(x%17==0) return mul(f[17],inv(x/17)); if(x%19==0) return mul(f[19],inv(x/19)); return fpow(x,mod-2); } co int L=1e6; int main(){ freopen("ftab.in","w",stdout); f[0]=f[1]=1; for(int i=2;i<N;++i) f[i]=mul(mod-mod/i,f[mod%i]); int sum=0; printf("%d,",sum); for(int i=1;i<=1e9;++i){ sum=add(sum,mul(i-1,mul(inv(i+1),inv(i+2)))); if(i%L==0) printf("%d,",sum); if(i%(10*L)==0) cerr<<i<<endl; if(i%(100*L)==0) puts(""); } return 0; }
大常数(主要是L设的太大)代码
co int L=1e6; int f[1001]={}; int sum(int n){ int ans=f[n/L]; for(int i=n/L*L+1;i<=n;++i) ans=add(ans,mul(i-1,mul(fpow(i+1,mod-2),fpow(i+2,mod-2)))); return ans; } int main(){ freopen("func.in","r",stdin),freopen("func.out","w",stdout); int n=read<int>(),m=read<int>(); int ans=add(sum(n-1),mod-sum(m)); ans=mul(ans,mul(n,n+1)); printf("%d\n",add(n-1,mul(2,mul(fpow(n,mod-2),ans)))); return 0; }
乔治的重病
Mio 是个带孝子,他搜集了 n 种药材,第 i 味药有 pi 的概率使乔治被治好。他要将这 n 种药材中的一部分组合在一起(每味药的效果独立,且最多只能用一次)。俗话说是药三分毒,Mio 希望他的父亲只被治好一次。
\(n \leq 10^4\)。
HDU6693 Valentine's Day
假设选了集合 \(S\),答案可以表示为
设现有的 \(\sum_{i\in S}\frac{p_i}{1-p_i}=X,~\prod_{i\in S}(1-p_i)=Y\),假设加入了新的物品 \(i\),那么新答案为
新旧答案变化量为
显然 \(X \geq 1\) 时加入任何物品都不会使得答案变忧。类似的,如果删除一个物品后 \(X \geq 1\),那么删除这个物品不会使答案变差。因此,任意一个最优解对应的非空药材集合 \(G\) 都满足 \(X \geq 1\),且该集合每个真子集均有 \(X<1\),也即
不难发现 \(\frac{p_i}{1−p_i}\) 和 \(p_i\) 的单调性相同。因此,如果一个满足上述条件的非空集合 \(G\) 不是由使乔治痊愈概率最大的若干个物品构成,那么可以把集合内概率最小的物品 \(a\) 换成集合外概率最大的物品 \(b\), 从而得到一个答案不会更劣的集合 \(G \backslash \{a\} \cup \{b\}\)。设新集合中概率最小的物品为 \(c\),新集合的真子集 \(G \backslash \{a\} \cup \{b\} \backslash \{c\}\) 可能不满足 \(X<1\),此时可以不断地删去集合中概率最小的物品,直到该集合满足条件。这个过程不会使答案变劣,不断地替换和删除药材可以得到最优解。
最终的结论是,按照概率从大到小的顺序购买药材直到 \(X \geq 1\) 或者全部买完为止,即可得到一个最优解。
时间复杂度 \(O(n \log n)\)。
co int N=10000+10; LD p[N]; int main(){ freopen("ill.in","r",stdin),freopen("ill.out","w",stdout); int n=read<int>(); for(int i=1;i<=n;++i) scanf("%Lf",p+i); sort(p+1,p+n+1,greater<LD>()); LD ans=0; LD X=0,Y=1; for(int i=1;i<=n;++i){ if(p[i]==1) {ans=1;break;} X+=p[i]/(1-p[i]),Y*=(1-p[i]); ans=max(ans,X*Y); } printf("%.*Lf",read<int>(),ans); return 0; }
石鬼面
Mio 涂在面具上的血可以看做由 n 个血滴构成的序列,共有 m 种颜色。
Mio 可以改变血滴的颜色,他想知道一个区间里有多少种颜色的血滴。
他进行了 q 次操作,修改一个点的颜色或者查询一个区间内出现的颜色种数。
一次操作输入格式为 op x y
- op=1 时,将从左往右第 x 个血滴颜色改为 y。
- op=2 时,查询区间[x,y]内有多少种颜色的血滴。
题解
经典题。想方设法维护last即可,分块,树套树,线段树分治均可。
我用的是分块,\(O(n \sqrt{n})\)。
co int N=100000+10,M=316+10; int n,m,Q; int a[N],lst[N]; set<int> s[N]; int blo,num; int le[M],ri[M],bl[N]; int cnt[M][N],tag[M][M]; void modify(int id,int p,int v){ for(int i=p;i<=ri[bl[p]];++i) cnt[id][i]+=v; for(int i=bl[p]+1;i<=num;++i) tag[id][i]+=v; } int main(){ freopen("mask.in","r",stdin),freopen("mask.out","w",stdout); read(n),read(m),read(Q); for(int i=1;i<=m;++i) s[i].insert(0),s[i].insert(n+1); for(int i=1;i<=n;++i) read(a[i]),lst[i]=*--s[a[i]].lower_bound(i),s[a[i]].insert(i); blo=sqrt(n),num=(n+blo-1)/blo; for(int i=1;i<=num;++i){ le[i]=ri[i-1]+1,ri[i]=min(i*blo,n); for(int j=le[i];j<=ri[i];++j) bl[j]=i,++cnt[i][lst[j]]; for(int j=1;j<=n;++j) cnt[i][j]+=cnt[i][j-1]; } // cerr<<"last="; // for(int i=1;i<=n;++i) cerr<<" "<<lst[i]; // cerr<<endl; while(Q--){ if(read<int>()==1){ int p=read<int>(),v=read<int>(); if(a[p]==v) continue; s[a[p]].erase(p),modify(bl[p],lst[p],-1); int q=*s[a[p]].upper_bound(p); if(q<=n){ modify(bl[q],lst[q],-1); lst[q]=lst[p],modify(bl[q],lst[q],1); } a[p]=v,s[v].insert(p); lst[p]=*--s[v].lower_bound(p),modify(bl[p],lst[p],1); q=*s[v].upper_bound(p); if(q<=n){ modify(bl[q],lst[q],-1); lst[q]=p,modify(bl[q],lst[q],1); } } else{ int l=read<int>(),r=read<int>(); int ans=0; if(bl[l]==bl[r]){ for(int i=l;i<=r;++i) ans+=lst[i]<l; printf("%d\n",ans); continue; } for(int i=l;i<=ri[bl[l]];++i) ans+=lst[i]<l; for(int i=bl[l]+1;i<=bl[r]-1;++i) ans+=cnt[i][l-1]+tag[i][bl[l-1]]; for(int i=le[bl[r]];i<=r;++i) ans+=lst[i]<l; printf("%d\n",ans); } } return 0; }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步