1113比赛总结

1 抓球

题面不说了,就是一道普通的概率DP,可惜我求范围的时候没有看清xi,yi的巨大范围,暴力求概率,结果炸裂了。所以教训是,教训之一是数据范围不一定是从小到大的范围来的,其二是不能只看N,M等的范围。

X连通块计数
时间限制 : - MS   空间限制 : - KB 
评测说明 : 1s,128m
问题描述

给出一棵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英雄新技
时间限制 : - MS   空间限制 : 165536 KB 
评测说明 : 1000ms
问题描述

老张也准备沉迷于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();q.pop();book[t]=0; cnt[t]++; for(int i=last[t];i;i=e[i].next){ int s=e[i].to;int l=e[i].len; if(dis[t]+l<dis[s]){ dis[s]=dis[t]+l; if(book[s]==0){ q.push(s);book[s]=1; if(cnt[s]>n+1){ ss=0;return; } } } } } } int judge(int mid){ int i,j; memset(e,0,sizeof(e));memset(last,0,sizeof(last));tot=0; for(i=1;i<=m;i++){ add(lx[i],ly[i],wei[i]-mid); } for(i=1;i<=n;i++)add(0,i,0); ss=1;spfa(); //cout<<ss<<endl; if(ss==0)return 0; int maxn=-1,minn=0x3f3f3f3f; for(i=1;i<=n;i++){ maxn=max(maxn,dis[i]); minn=min(minn,dis[i]); } //cout<<maxn<<" "<<minn<<endl; //if(maxn-minn<=20000)return 1; return 1; } int ef(int l,int r){ int mid; while(l<r){ mid=(l+r+1)>>1; if(judge(mid)==1)l=mid; else r=mid-1; } return l; } int main() { //freopen("newhero.in","r",stdin); //freopen("oops.txt","w",stdout); while(scanf("%d%d",&n,&m)!=EOF) { int i,j,k,a,b,c; memset(lx,0,sizeof(lx));memset(ly,0,sizeof(ly));memset(wei,0,sizeof(wei)); for(i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c);lx[i]=a;ly[i]=b;wei[i]=c; } //cout<<judge(2418)<<endl; //for(i=1;i<=n;i++)cout<<dis[i]<<" "; if(judge(1)==0){ cout<<"No Solution"<<endl;continue; } if(judge(10001)==1){ cout<<"Infinite"<<endl;continue; } cout<<ef(1,10000)<<endl; } return 0; } 

猜你喜欢

转载自www.cnblogs.com/pepparan/p/11854586.html