恩欧挨批模拟试题-13
作者:互联网
水博客太快乐了
考场
先看 \(T1\) ,哇这不是个大水题!!!
直接快速幂加组合数上。
写一半发现忘了怎么线性求逆元了。。。。
推了半天式子才想起来。。。。(那为什么不用费马小定理呢?
感觉肯定过了。。。
再看 \(T2\) ,没啥思路。。。。
(想到了基环树,但是以为图不连通,是个森林。。。基环树也不好处理。。果断放弃。。。没往下想。。。
再看 \(T3\) ,没啥思路。。。。
式子也不会推。。。。
最后 \(T2\) \(T3\) 糊了两个暴力上去。。。。
分数
预估 : \(t1\) \(100pts\) \(+\) \(t2\) \(30pts\) \(+\) \(t3\) \(40pts\) \(=\) \(170pts\)
实际 : \(t1\) \(80pts\) \(+\) \(t2\) \(20pts\) \(+\) \(t3\) \(30pts\) \(=\) \(130pts\)
发现 \(T1\) 挂了两个点,发现少模 \(+\) \(0\)的逆元忘赋成 \(1\) 。。。
题解
A. 工业题 / a
全场最水的一题,想象一个矩阵,已知最下面的一行与最左边的一列,要求点 \((n,m)\) 的值。
直接算出边上每一个点对最终答案的贡献。
没啥难度。。。放下式子就好了。
\(ans = \sum_{i=1}^{i \le n} f_{i,0} \times a^{m} \times b^{n-i} \times C_{m-1}^{n-i+m-1} + \sum_{i=1}^{i \le m} f_{0,i} \times b^{n} \times a^{m-i} \times C_{n-1}^{m-i+n-1}\)
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10, mod=998244353;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int inv[N], mul[N], inv1[N];
inline void pre(int n){
inv[0]=mul[1]=inv[1]=inv1[1]=inv1[0]=1;
for(int i=2; i<=n; ++i){
inv1[i]=((-mod/i+mod)*inv1[mod%i])%mod;
mul[i]=(i*mul[i-1])%mod;
inv[i]=(inv[i-1]*inv1[i])%mod;
}
}
inline int qp(int n, int m){
int ans=1;
while(m){
if(m&1) ans*=n, ans%=mod;
m>>=1; n*=n; n%=mod;
}
return ans;
}
int C(int n, int m) { return n<=m ? 1 : (((mul[n]*inv[m])%mod)*inv[n-m])%mod; }
int n, m, a, b;
int f1[N], f2[N], ans;
signed main(void){
n=read(); m=read(); pre(n+m);
a=read()%mod, b=read()%mod;
for(int i=1; i<=n; ++i) f1[i]=read()%mod;
for(int i=1; i<=m; ++i) f2[i]=read()%mod;
for(int i=1; i<=n; ++i){
ans+=(((((f1[i]*qp(a, m))%mod)*qp(b, n-i))%mod)*C(n-i+m-1, m-1))%mod;
ans%=mod;
}
for(int i=1; i<=m; ++i){
ans+=(((((f2[i]*qp(b, n))%mod)*qp(a, m-i))%mod)*C(m-i+n-1, n-1))%mod;
ans%=mod;
}
printf("%lld\n", ans);
return 0;
}
B. 卡常题 / b
直接算貌似很麻烦,考虑转化。
计算出点权,将每次给出的两个 \(X\) 点直接连边,就避免了出现 \(Y\) 点,得到了一课基环树。
基环树上每一条边意义为所连接的两个点中,至少选择其中一个。
求选择树上哪些点可以满足上述关系且使点权和最少。
基环树的常见操作,换上随便断一条边 \((u,v)\) 形成一棵树,树上 \(DP\) 即可。
这个树上 \(DP\) 很套路,直接乱搞即可,令 \(f_{u,0}\) 表示不选当前点,子树的最小点权和, \(f_{u,1}\) 表示选当前点,子树的最小点权和,然后再乱搞就可以了。
但是因为删除了一条边,直接 \(DP\) 很可能不能满足选择了 \(u, v\) 中的一个,因此以 \(u\) 和 \(v\) 分别为根跑一次 \(DP\) ,再在 \(f_{u,1}\) 与 \(f_{v,1}\) 中取较小值即可。
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, a, b, ans;
int x, y, u, v;
vector<int> l[N];
int f[N][2], val[N];
void dfs(int u, int fa){
f[u][1]=val[u]; f[u][0]=0;
for(int i=0; i<l[u].size(); ++i){
int v=l[u][i];
if(v==fa) continue;
dfs(v, u); f[u][0]+=f[v][1];
f[u][1]+=min(f[v][1], f[v][0]);
}
}
int fa[N];
int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
int main(void){
n=read(); a=read(); b=read();
for(int i=1; i<=n; ++i) fa[i]=i;
for(int i=1; i<=n; ++i){
x=read(), y=read();
val[x]+=a; val[y]+=b;
if(find(x)==find(y)) { u=x, v=y; continue; }
l[x].push_back(y); l[y].push_back(x);
fa[find(x)]=find(y);
}
dfs(u, 0); ans=f[u][1];
dfs(v, 0); ans=min(ans, f[v][1]);
printf("%d\n", ans);
return 0;
}
C. 玄学题 / c
这个题解写的异常的清楚。。。。
因此直接把题解 \(Ctrl\) \(C\) \(+\) \(Ctrl\) \(V\) 下来就好了。。。。
主要是因为懒
那个-1 的幂是由 \(d(i*j)\) 的和的奇偶性决定的。
d(x)为偶数时并没有任何影响,我们只考虑 \(d(x)\) 为奇数的时候,
不难想到,x 这个时候是完全平方数。
我们把 i 拆成 \(p*q^{2}\) ( $p4 没有平方因子),那 \(j\) 必须有 \(p*r^{2}\) 的
形式,所以对于每个 \(i\),都有 \(\sqrt{ \frac{m}{p} }\) 个 \(j\) 产生贡献。
至于 \(p\) 的求法,线性筛即可。
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
inline long long read(){
long long f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int pri[N], cnt, mn[N];
bool p[N];
inline void sieze(int n){
mn[1]=1;
for(int i=2; i<=n; ++i){
if(!p[i]) pri[++cnt]=i, mn[i]=i;
for(int j=1; j<=cnt&&i*pri[j]<=n; ++j){
p[i*pri[j]]=1; mn[i*pri[j]]=mn[i]*pri[j];
if(mn[i]%pri[j]==0) mn[i*pri[j]]/=pri[j]*pri[j];
if(i%pri[j]==0) break;
}
}
}
int n, ans;
long long m;
signed main(void){
ans=n=read(), m=read(); sieze(n+1);
for(int i=1; i<=n; ++i){
int ul=sqrt(m/mn[i]);
ans-=(ul&1)<<1;
}
printf("%d\n", ans);
return 0;
}
标签:10,13,挨批,int,long,times,ch,恩欧,getchar 来源: https://www.cnblogs.com/CTcode/p/NOIP_13.html