20260728考试总结
P4427 [BJOI2018] 求和
简化题意
给定一颗 \(n\) 个节点的树,每个节点有个权值 \(a_i\),给定树上路径 \(l-r\)(这里记为 \(s\)),请你求出 \(\textstyle \sum_{i \in s}^{a_i^k}\)(\(k\)已知)
做法
注意到 \(k\) 比较小,所以我们可以考虑去与处理所有的 \(k\) 的树上前缀和,使用 \(LCA\) 查询即可,这里需要统计的是点的和,所以运用公式 sum[k][l]+sum[k][r]-sum[k][lca]-sum[k][dp[lca][0]]。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=300005,mod=998244353;
int qpow(int x,int y){
int ans=1;
while(y){
if(y&1)ans=ans*x%mod;
x=x*x%mod;y>>=1;
}
return ans;
}
int n,m;
vector<int>g[N];
int dp[N][25];
int dep[N];
int sum[55][N];
void dfs(int u,int fa){
dp[u][0]=fa;
for(int i=1;i<=20;i++)dp[u][i]=dp[dp[u][i-1]][i-1];
for(auto i:g[u]){
if(i!=fa){
dep[i]=dep[u]+1;
dfs(i,u);
}
}
return;
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--){
if(dep[dp[x][i]]>=dep[y])x=dp[x][i];
}
if(x==y)return x;
for(int i=20;i>=0;i--){
if(dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];
}
return dp[x][0];
}
void init(int u,int fa){
int jc=1;
for(int i=1;i<=50;i++){
jc*=dep[u];jc%=mod;
sum[i][u]=(sum[i][fa]+jc)%mod;
}
for(auto i:g[u]){
if(i!=fa)init(i,u);
}
return;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("sum.in","r",stdin);
// freopen("sum.out","w",stdout);
cin>>n;
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);init(1,0);
cin>>m;
for(int i=1;i<=m;i++){
int l,r,k;cin>>l>>r>>k;
int lca=LCA(l,r);
cout<<((sum[k][l]+sum[k][r]-sum[k][lca]-sum[k][dp[lca][0]])%mod+mod)%mod<<"\n";
}
return 0;
}
P1514 [NOIP 2010 提高组] 引水入城
简化题意
有一个矩形,矩形上的格子有不同高度。你可以在第一行的任意多个格子放水,水会沿低的格子一直落下来。
求最少需要放多少水才能使得最后一行都有水,如果不能,则有多少格子没有水
题解
可以发现有一个性质,就是如果有解,则一个点覆盖的应定是一个区间。
证明
这里考虑使用反证法。
假设这是一条水流

没有线条则表示无法抵达,因为一定有解,所以将会有旁边的一条河流到达这个点

而这条红色的河,经过了蓝色的河之后才到达点,但是蓝色河流是无法到达的,因此矛盾。
(这里借用了这篇文章)的图片
所以我们可以考虑对于第一行的每个点,运用记忆化搜索求出可以到达的最后一行的左右点。最后通过一个最小线段覆盖求解答案即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=505;
struct no{
int l,r;
}t[N][N];
int h[N][N];
int sum[N];
bool vis[N][N];
int n,m;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void dfs(int x,int y){
vis[x][y]=1;
for(int i=0;i<4;i++){
int zx=x+dx[i],zy=y+dy[i];
if(zx>=1 && zx<=n && zy>=1 && zy<=m && h[x][y]>h[zx][zy]){
if(!vis[zx][zy])dfs(zx,zy);
t[x][y].l=min(t[x][y].l,t[zx][zy].l);
t[x][y].r=max(t[x][y].r,t[zx][zy].r);
}
}
return;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cin>>h[i][j];
}
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)t[i][j].l=1e9;
for(int i=1;i<=m;i++)t[n][i]={i,i};
for(int i=1;i<=m;i++){
if(!vis[1][i])dfs(1,i);
}
int ans=0;
for(int i=1;i<=m;i++)ans+=!vis[n][i];
if(ans){
cout<<0<<"\n"<<ans;
return 0;
}
int x=0,top=1;
while(x<m){
ans++;
int lasr=x+1;
for(int i=1;i<=m;i++){
if(t[1][i].l<=lasr)x=max(x,t[1][i].r);
}
}
cout<<1<<"\n"<<ans;
return 0;
}

浙公网安备 33010602011771号