CSP-S模拟18
前言:
哈哈

\(But...\)

疑似\(oi\)重拳出击.....
以及这场比赛的题目名字,看得出来出题人已经很绝望了

\(T1:\) 题目(\(problem\))【又名:T648878 序列统计】
前言:
一定要好好算时间复杂度啊!!因为看到\(n≤8\),所以写完\(dfs\)就跑,结果....丢了个\(0\)(其实有一部分原因是我不会算👉👈)

思路:
其实也是\(dfs\),不过正常的\(dfs\)会像我一样\(T\)掉,所以我们要写\(meet-in-the-middle\)(折半搜索),然后就没啦。
代码:
点击查看代码
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=10;
int n,s,a[N],ans[1<<20],tot,cnt;
inline void dfs1(int pos,int sum){
if(pos>(n+1)>>1){
ans[++tot]=sum;//把前一半可能的情况存起来
return ;
}int num=1;
while(1){
num*=a[pos];
if(num+sum>s) break;
dfs1(pos+1,sum+num);
}
}//前一半
inline void dfs2(int pos,int sum){
if(pos>n){
cnt+=upper_bound(ans+1,ans+1+tot,s-sum)-ans-1;//总计有多少种情况满足题意
return ;
}int num=1;
while(1){
num*=a[pos];
if(num+sum>s) break;
dfs2(pos+1,sum+num);
}
}//后一半
signed main(){
// freopen("problem.in","r",stdin);
// freopen("problem.out","w",stdout);
ios::sync_with_stdio(false);
cin>>n>>s;
for(int i=1;i<=n;i++) cin>>a[i];
dfs1(1,0);
sort(ans+1,ans+1+tot);//排序 方便查找
dfs2(((n+1)>>1)+1,0);
cout<<cnt<<'\n';//输出答案
return 0;
}
\(T2:\) 名字(name)【与此题相似】
前言:
此题长着一副人畜无害的样子,(却干着杀人放火的勾当) 但怒调两小时无果呜呜呜。赛后一看题解,确实是我高攀不起的亚子。依据同机房大佬简单易懂的讲解,我觉得我应该是悟了。
思路:
我们不难知道\(dis_{u,v}=dep_u+dep_v-2*dep_{lca(u,v)}\),然后由期望的线性可得我们要求的东西就是\(E(dep_u+dep_v-2*dep_{lca(u,v)})~=~E(dep_u) ~ + ~ E(dep_v) ~ ~ - ~2*E(dep_{lca(u,v)})\)。其中,\(E(dep_u)\)很好求[ 我不造啊,ta们说滴 ] ,显然由题意可得,\(dep_i=\sum_{j=1}^{i-1}\frac{a_j}{sum_{i-1}}(dep_j+b_i+b_j)=\frac{\sum_{j=1}^{i-1}a_j*(dep_j+b_j)+\sum_{j=1}^{i-1}a_j*b_i}{sum_{i-1}}\),显然,\(\sum_{j=1}^{i-1}a_j*(dep_j+b_j)\)这一坨可以用前缀和进行优化。
接着我们来看\(E(dep_{lca(u,v)})\),我们不妨令\(u<v\),那么显然\(lca(u,v)\) 只与\(u\)有关。为什么捏?我们假设\(u<v\)(如果不小于的话互换一下不就好了),那么\(lca_{u,v}\)一定为\(1\) ~ \(u-1\)中的一个值,即无论\(v\)为多少,只要\(u\)值一定,那么就会有一个对应的\(lca_{u,v}\),于是我们可以得到式子啦(式子中的\(i\)为上述的\(u\)):\(lca_i=\sum_{j=1}^{i}\frac{a_j}{sum_{i}}*lca_j=\frac{\sum_{j=1}^{i-1}a_j*lca_j+dep_i*a_i}{sum_{i}}\),然后用前缀和优化一下就可以啦~~
最后再输出答案\(E(dep_u) ~ + ~ E(dep_v) ~ ~ - ~2*E(dep_{lca(u,v)})\)就完结撒花啦~~✿✿ヽ(°▽°)ノ✿
代码时间:
code time
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=3e5+10,mod=1e9+7;
int n,q,x,y,css;
int a[maxn],b[maxn],sum[maxn],dep[maxn],lca[maxn];
inline int qpow(int x,int y){
int res=1;
while(y){
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}//快速幂
signed main(){
// freopen("name.in","r",stdin);
// freopen("name.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i) cin>>b[i];
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];//前缀和
dep[1]=1;css=a[1]*(1+b[1])%mod;
for(int i=2;i<=n;i++){
dep[i]=(css+sum[i-1]*b[i]%mod)%mod*qpow(sum[i-1],mod-2)%mod;
css=(css+a[i]*(b[i]+dep[i])%mod)%mod;//存dep[j] 前缀和优化
}css=a[1];lca[1]=1;
for(int i=2;i<=n;i++){
lca[i]=(css+dep[i]*a[i]%mod)*qpow(sum[i],mod-2)%mod;//因为i的lca不包含i所以这里的分母为sum[i]
css=(css+lca[i]*a[i]%mod)%mod;//前缀和优化
}
for(int i=1;i<=q;i++){
cin>>x>>y;
if(x==y){
cout<<0<<'\n';
continue;
} //特判
cout<<((dep[x]+dep[y]-2*lca[x]%mod)%mod+mod)%mod<<'\n';//输出答案
}
return 0;
}
\(T3:\) 好难(toohard)
前言:
跟我的心情那是一样一样滴,但是吧,我不会,就不写了吧
\(T4:\) 取啊(select)
前言:
不会+10086