1113比赛总结
1 抓球
题面不说了,就是一道普通的概率DP,可惜我求范围的时候没有看清xi,yi的巨大范围,暴力求概率,结果炸裂了。所以教训是,教训之一是数据范围不一定是从小到大的范围来的,其二是不能只看N,M等的范围。
X连通块计数 | ||
|
问题描述
给出一棵n个点的树,每个点有一个权值ai。从这棵树上选出一个点集,使得选出的点连通,且满足点集中的点的权值最大值与最小值之差不超过k,问有多少种选点集的办法。
两种选点集的办法不同当且仅当点集中的点的标号不同。
输入格式
第一行,包含两个整数n,k。
第二行,包含n个整数a1, a2, · · · , an。
接下来n − 1行,每行包含两个正整数u, v,表示u, v两点间有一条边。
输出格式
仅输出一行,包含一个数,表示选点集的办法。
这个数可能很大,输出时对1000000007取模。
样例输入 1
4 1
2 1 3 2
1 2
1 3
3 4
样例输出 1
8
这道题由于有点权,让我想到DP,但是如果把状态定成差值,就很难转移,就卡住了。
由于这题的难点在于确定最大最小点的位置,所以我们定f[i]为以i为根的子树的方案数
不难想到转移方程:f[i]=π(f[j]+1)
还有一个问题就是差值的限制,我开始想把它定入状态,但是无法转移
但是注意,题目说的是“连通块”,这意味着根节点是不确定的。
我们只要枚举每一个点x为根,以它为最大值,这样只要满足任意v[x]-k<=v[y]<=v[x]就可以了
但是,当两个相邻的点权值一样时,它们可能会互相搜到。
这时候我们人为地定下优先度,一个点只能搜比它编号小的点,问题解决
回头来看,除了一个树的遍历,这道题没有用任何高级算法,但是蕴含着“化动为静”的思想
既然不能确定哪一个点是最大点,我们就令每一个点为最大点
既然可能存在重复计算,我们就为计算制定限制和规则
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{
ll to;ll next;
}e[4010];
ll last[2010],tot;
void add(ll x,ll y){
e[++tot].to=y;
e[tot].next=last[x];
last[x]=tot;
}
ll n,k,a[2010],f[2010],mod=998244353;
ll dfs(ll x,ll fa,ll root){
ll tot=1;
for(ll i=last[x];i;i=e[i].next){
ll y=e[i].to;
if(y!=fa&&a[root]>=a[y]&&a[root]-a[y]<=k&&(root>y||a[root]!=a[y])){
tot=(tot*(dfs(y,x,root)+1))%mod;
}
}
return tot;
}
int main()
{
ll i,j,x,y;
scanf("%lld%lld",&n,&k);
for(i=1;i<=n;i++)scanf("%lld",&a[i]);
for(i=1;i<=n-1;i++){
scanf("%lld%lld",&x,&y);
add(x,y);add(y,x);
}
ll ans=0;
for(i=1;i<=n;i++){
ans+=dfs(i,i,i);ans%=mod;
//cout<<dfs(i,i,i)<<endl;
}
cout<<ans<<endl;
return 0;
}
W英雄新技 | ||
|
问题描述
老张也准备沉迷于lol不能自拔。为了表示自己的诚意,老张设计了一个新英雄。这个新英雄的大招非常强势,在追人的时候能体现非常强的优势。假设召唤师峡谷是一个有n个节点,m条单向边的图。对于每一个节点x,可以把所有以x为终点的边的权值减少d(-10000<=d<=10000),同时把所有以x为起点的边的权值加上d。要让所有边的权值的最小值最大。当然,边的权值不能为负,因为这不符合召唤师峡谷的物理规律。
输入格式
有多组数据,对于每一组数据:
第一行为两个整数n,m
接下来m行,每一行三个整数a,b,c 表示从a到b有一条长度为c的道路
输出格式
对于每一个数据块输出文件仅有一行:
如果答案有且仅有一个解,输出最短道路的最大可能值
如果答案具有任意性,即有多解,输出”Infinite”
如果无解,输出”No Solution”
样例输入
2 1
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1
样例输出
Infinite
Infinite
3
1
提示
n≤500,m≤2700,-10000<=d<=10000每条道路的长度保证不超过10000
题意大概就是每个点的所有入边和出边可以任意零和变化,求最小边的最大值
此题虽然以无向图为背景,但与一般的图论颇为不同
看到最小值最大,自然想到二分答案。二分后怎么判断,这时候差分约束粉墨登场!!
一般我们用差分约束系统都是求最大或最小值,判断是否有解要少见一些,但是也不能忽视。
说不定下次会出一个判断是否有任意解的。
这道题判断两种特殊情况把我弄炸了
其实对于二分来说很好判断,只要在二分下界仍然不满足条件,就是无解;在上界+1位置还是满足条件,就有任意解
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,k=1;char ch;
ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')k=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*k;
}
struct node{
int to;int next;int len;
}e[6010];
int last[510],tot;
void add(int x,int y,int z){
e[++tot].to=y;
e[tot].len=z;
e[tot].next=last[x];
last[x]=tot;
}
int n,m,lx[6010],ly[6010],wei[6010];
int dis[510],book[510],cnt[510],ss;
queue<int>q;
void spfa(){
memset(dis,0x3f,sizeof(dis));memset(book,0,sizeof(book));memset(cnt,0,sizeof(cnt));
while(q.size())q.pop();
dis[0]=0;q.push(0);book[0]=1;
while(q.size()){
int t=q.front(