AtCoder Beginner Contest 237 VP补题

32 篇文章 0 订阅
31 篇文章 0 订阅

E

大意:
给定一张无向图,两点间的边权:

较高点到较低点的边权等于高度差

较低点到较高点的边权等于高度差的负二倍

求:图中的最大dis值

思路:
按题意建边即可;

但是有负权,所以一般的dij不行。

赛后又加强过数据,所以我跑了spfa,T烂了。。。(但是我看有一个哥们还真用spfa冲过去了。。。【崩溃】)

官方题解的思路是dij

考虑“势”的思想(绝):

对数据进行预处理,高点到低点的边权等于0,低点到高点的距离等于高度差(>=0)

那么就全是非负权边了。

跑完dij后只要把数据还原回去就可以了,dis[i]=h[i]-h[1]+dist[i]

code:

再说

F

大意:

求长度为 n,每个元素不大于m的序列,满足以下条件的有多少种:
最长上升子序列长度恰好为3.

思路:
m很小,只有10,那么久很容易想到暴力枚举+dp

不妨设i代表当前枚举到的数列长度,k1 表示当前序列长度为1的LIS的最后一个元素的最小值,k2 表示当前序列长度为2的LIS的最后一个元素的最小值,k3 则表示当前序列长度为3的LIS的最后一个元素的最小值

那么dp[i][k1][k2][k3]就代表对应情况的方案数。

那么每次再多枚举一个x,对x的大小进行分类讨论即可。

细节见code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1005;
const ll mod=998244353;
ll dp[N][12][12][12];
ll n,m;
int main()
{
	cin>>n>>m;
	dp[0][m+1][m+1][m+1]=1;
	for(int i=1;i<=n;++i)
	{
		for(int k1=1;k1<=m+1;++k1)
		{
			for(int k2=1;k2<=m+1;++k2)
			{
				for(int k3=1;k3<=m+1;++k3)
				{
					for(int x=1;x<=m;++x)
					{
						if(x<=k1) dp[i][x][k2][k3]=(dp[i-1][k1][k2][k3]+dp[i][x][k2][k3])%mod;
						else if(x<=k2) dp[i][k1][x][k3]=(dp[i-1][k1][k2][k3]+dp[i][k1][x][k3])%mod;
						else if(x<=k3) dp[i][k1][k2][x]=(dp[i-1][k1][k2][k3]+dp[i][k1][k2][x])%mod;
					}
				}
			}
		}
	}
	ll ans=0;
	for(int k1=1;k1<=m;++k1)
	{
		for(int k2=1;k2<=m;++k2)
		{
			for(int k3=1;k3<=m;++k3)
			{
			//	cout<<dp[n][k1][k2][k3];
				ans=(ans+dp[n][k1][k2][k3])%mod;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
 } 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值