东北林业大NEFU 五一欢乐水题 F&H题解

比赛链接

H卡迪亚的游戏

这题一看,零一背包的皮,然后无论是回溯做法的O(2^n)还是正常dp的O(VN)都满足不了这些毒瘤数据,过于生草,然后神勇的队友竟然设dp[i][j]为前i个物品价值为j的情况下的最小重量。时间复杂度一下子变成O(n*价值最大值),才1e4。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x3f3f3f3f; 
int w[105],v[105];
int dp[105][10005];
int main(){
	int n,W;
	scanf("%d %d",&n,&W);
	for (int i=1;i<=n;i++)
		scanf("%d %d",&w[i],&v[i]);	
	for (int i=0;i<=n;i++)
		for (int j=0;j<=n*100;j++)
			dp[i][j]=inf;
	dp[0][0]=0;
	for(int i=1;i<=n;i++){
        for(int j=0;j<=n*100;j++)
            dp[i][j]=min(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
    }
    int ans=0;
    for(int i=0;i<=n*100;i++)
		if (dp[n][i]<=W) ans=i;
	printf("%d",ans);
}

F我要去看流星雨

这个题可以先找有哪几对点满足引力差不大于M的,也可以先找相邻点;最后来一个并查集求联通块就行了。师兄先找后者,他说散列再散列,然后给出华丽的code说:“stl大赛”

师兄的做法和我是殊途同归的,我先求引力差不超过M的pair,这个求法就很好求了,开一个结构体按照v大小sort一下就行了,用Next数组来标记当前点满足引力差小于等于M的点区间是多少,因为代码有点长就注释了一下,看注释问题不大就不细说。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <queue>
#include <stack>
#include <map>
//
using namespace std;
const int INF = 0x3f3f3f3f;//1.06e9大小
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
const int mod3 = 1e9;
const double PI = 3.14159265;
const double eps =1e-8;
typedef unsigned long long ULL;
typedef long long LL;
//
struct note
{
	int x,y,z,v;
};
note a[10001];
int fa[10001];
int Next[10001];
int tong[10001];
bool cmp(note x,note y)
{
	return x.v>y.v;
}

int getfa(int k)
{
	return fa[k]==k?k:fa[k]=getfa(fa[k]);
}

void mer(int x,int y)
{
	int a=getfa(x);
	int b=getfa(y);
	fa[a]=b;
}

bool check(int i,int j)
{
	int cnt=0;
	int flag=0;
	if(a[i].x==a[j].x)++cnt;
	if(a[i].y==a[j].y)++cnt;
	if(a[i].z==a[j].z)++cnt;
	if(abs(a[i].x-a[j].x)==1)flag=1;
	if(abs(a[i].y-a[j].y)==1)flag=1;
	if(abs(a[i].z-a[j].z)==1)flag=1;
	if(cnt==3)return true;
	if(cnt==2&&flag)return true;
	return false;
}

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;++i)fa[i]=i;
	for(int i=1;i<=n;++i)
	{
		scanf("%d %d %d %d",&a[i].x,&a[i].y,&a[i].z,&a[i].v);
	}
	sort(a+1,a+1+n,cmp);
	int j=2;
	for(int i=1;i<=n;++i)
	{
		while(j!=n+1&&a[i].v-a[j].v<=m)++j;
		Next[i]=j;//求第i个点i能和(i,j)区间之间的点链接.
	}
	for(int i=1;i<n;++i)
	{
		for(int j=i+1;j<Next[i];++j)
		{
			if(check(i,j))mer(i,j);//链接所有引力差小于等于m同时相邻的点。
		}
	}
	int cnt=0;//连通块的数量;
	int MAX=0;
	for(int i=1;i<=n;++i)
	{
		if(tong[getfa(i)]==0)++cnt;
		tong[getfa(i)]++;
		MAX=max(MAX,tong[getfa(i)]);
	}
	printf("%d %d\n",cnt,MAX);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值