2020级训练赛10.23

最优卡组

一、题目

题目描述
chitanda k k k 个卡包,第 i i i 个卡包里有 c i c_i ci 张卡,每张卡有一个能力值,其中第 i i i 个卡包里的第 j j j 张卡具有 a i , j a_{i, j} ai,j 点能力值。
他准备选择 k k k 张卡牌的组合,其中每个卡包要选择恰好一张卡牌。他希望这 k k k 张卡牌的能力值之和尽量大,请你告诉他在所有可能的组合里,能力值之和最大的 n n n 个组合分别具有多大的能力值。

输入格式
第一行包含两个整数 k k k n n n,含义见题目描述。
接下来 k k k 行,每行描述一个卡包的信息,其中第 i i i 行的第一个整数表示 c i c_i ci,接下来该行会有 c i c_i ci 个整数,依次表示这个卡包里每张卡的能力值。

输出格式
输出一行,包含 n n n 个整数,相邻两个数字之间用空格隔开,其中第 i i i 个整数表示第 i i i 大的能力值之和。

二、解法

0x01 暴力解决
绑点的东西最恶心 ,就是搜索加一些奇技淫巧 也得不了分( c l o r k _ t clork\_t clork_t是个好东西 )。
我们换一种搜索思路,避免扩展出不必要的状态。
我们定义状态为在每个卡包的选取状态,如 1231 1231 1231就是在第1个卡包中选第1大的,在第2个卡包中选第2大的 … … \dots\dots 发现每一种状态都是可以由其他状态转移过来,我们的搜索就是要让当前最优的状态去扩展它的后继,具体怎么实现能,我们维护一个优先队列,把最初状态塞进去,每次选最优的状态去扩展其他状态,把它们压入优先队列中(有点像 d i j k s t r a dijkstra dijkstra),每次取出的状态我们就把它算进答案里面,直到取到 n n n个,时间复杂度 O ( n k log ⁡ ) O(nk\log) O(nklog)

0x02 对暴力的优化
虽然我们上面的方法已经比无脑搜优秀很多了,但它还是免不了扩展出许多不必要的状态,我们尝试减少每个状态扩展出来的状态,就能减少时间复杂度,但是我们要考虑下列的两个原则:
1、所有状态必须能被不重复,不遗漏地扩展出来。
2、保证先扩展出来的状态一定由于后扩展出来的状态。
我们考虑一种很奇怪的贪心,先找到最后一位非1位(参照上文状态定义),我们就可以把这一位和下一位加1作为新的状态,如果该位是2的话,可以把它和后一位调换位置,这么就可以满足第一个原则,该算法时间复杂度为 O ( 3 n log ⁡ ) O(3n\log) O(3nlog),肯定过的了。
但是我们考虑条件二的时候,发现该算法不一定满足条件2,因为21(状态局部)不一定优于12,但12是由21扩展出来的,所以必须要满足21优于12,怎么解决这个问题呢?发现只要将卡包按最大值和最小值的差值从小到大排序即可(如果只有卡包里只有一个牌就不管),这样就保证了第二个原则。

0x03 后记及代码
其实作者讲的不是特别严谨,比如说该算法能满足第一个原则的证明,和想到这个算法的方法,都没有讲的很清楚,读者可以拿这位大佬的博客一起阅读。
日常贴代码qwq ?

#include <cstdio>
#include <vector>
#include <algorithm>
#include <queue>
#define int long long
using namespace std;
const int MAXN = 100005;
int read()
{
    int num=0,flag=1;
    char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int n,m,sum;
vector<int> a[MAXN],ans;
struct node
{
	int sum,pos,num;
	bool operator < (const node &B) const {
		return sum<B.sum;
	}
};
bool cmp1(int a,int b)
{
	return a>b;
}
bool cmp2(vector<int> a,vector<int> b)
{
	return a[0]-a[1]<b[0]-b[1];
}
signed main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		int k=read(),t=0,Max=0;
		while(k--)
		{
			a[i].push_back(t=read());
			Max=max(Max,t);
		}
		sum+=Max;
		if(a[i].size()==1)
		{
			a[i].clear();
			n--;i--;
			continue;
		}
		sort(a[i].begin(),a[i].end(),cmp1);
	}
	sort(a+1,a+1+n,cmp2);
	priority_queue<node> q;
	m--;
	q.push(node{sum-a[1][0]+a[1][1],1,2});
	ans.push_back(sum);
	while(m>0 && !q.empty())
	{
		node t=q.top();
		q.pop();
		ans.push_back(t.sum);
		m--;
		if(t.num<a[t.pos].size())
			q.push(node{t.sum-a[t.pos][t.num-1]+a[t.pos][t.num],t.pos,t.num+1});
		if(t.pos<n)
			q.push(node{t.sum-a[t.pos+1][0]+a[t.pos+1][1],t.pos+1,2});
		if(t.num==2 && t.pos<n)
			q.push(node{t.sum+a[t.pos][0]-a[t.pos][1]-a[t.pos+1][0]+a[t.pos+1][1],t.pos+1,2});
	}
	for(int i=0;i<ans.size();i++)
		printf("%lld ",ans[i]);
}

小奇探险

一、题目

题目描述
小奇去遗迹探险,遗迹里有 N N N 个宝箱,有的装满了珠宝,有的装着废品。
小奇有地图,所以它知道每一个宝箱的价值,但是它不喜欢走回头路,所以要按顺序拿这 N N N 个宝箱中的若干个。
拿宝箱很累的。一开始小奇的体力是 1 1 1,每得到一个宝箱之后,小奇得到的价值是体力 × \times × 宝箱的价值,之后它的体力就会变为原来的 k k k ( 0 < k < 1 ) (0<k<1) (0<k<1)
小奇不喜欢连续放过很多宝箱,所以任意一段长度为 M M M 的序列中,小奇一定要取走其中的一个宝箱。
现在小奇想知道它能得到的最大价值和。

输入格式
第一行,两个整数 N , M N,M N,M,表示的含义如题目中所述;
第二行,一个小数 k k k,表示的含义如题目中所述,最多 4 4 4 位小数;
第三行, N N N 个整数,第 i i i 个整数表示第 i i i 个宝箱的价值。

输出格式
输出一行,一个实数,表示小奇能得到的最大价值和,四舍五入保留两位小数。

数据范围
对于 30 % 30\% 30% 的数据,有 1 ≤ N ≤ 10 1\le N\le 10 1N10
对于 60 % 60\% 60% 的数据,有 1 ≤ N ≤ 1000 1\le N\le 1000 1N1000
对于 100 % 100\% 100% 的数据,有 1 ≤ N ≤ 100000 1\le N\le 100000 1N100000 1 ≤ M ≤ N 1\le M\le N 1MN 0 < k < 1 0<k<1 0<k<1 − 1 0 9 ≤ -10^9\le 109所有宝箱的价值 ≤ 1 0 9 \le 10^9 109

二、解法

一看这道题就是 d p dp dp,考试时无脑码了一发,优化也只有80分。
我们先不考虑 k k k的限制,因为这道题没有限制取宝箱的个数,我们定义 d p [ i ] dp[i] dp[i]为在第i个点拿宝箱,在前面也拿宝箱的最大总价值,则:
d p [ i ] = max ⁡ { d p [ j ] + a [ i ] } ∨ ( i − m < = j < i ) dp[i]=\max\{dp[j]+a[i]\}\vee (i-m<=j<i) dp[i]=max{dp[j]+a[i]}(im<=j<i)
这个 d p dp dp用滑窗来优化,可以做到 O ( n ) O(n) O(n)
我们考虑加入 k k k的限制,发现这样的话 d p dp dp就要增加一维(然后当场去世),现在我们考虑怎么处理 k k k的问题,发现这多的一维是用来解决个数的记录,我们可以模仿 h a s h hash hash的方式,从后往前 d p dp dp,则:
d p [ i ] = d p [ j ] × k + a [ i ] ∨ ( i < j < = i + m ) dp[i]=dp[j]\times k+a[i]\vee (i<j<=i+m) dp[i]=dp[j]×k+a[i](i<j<=i+m)
这样我们就可以避免个数的问题,时间复杂度还是 O ( n ) O(n) O(n)
??

#include <cstdio>
#include <cstring>
#include <iostream>
#define eps 1e-11
using namespace std;
const int MAXN = 100005;
int read()
{
	int x=0,flag=1;
	char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*flag;
}
int n,m,head,tail,a[MAXN],q[MAXN];
double ans,k,dp[MAXN];
int main()
{
	n=read();m=read();
	scanf("%lf",&k);
	for(int i=1;i<=n;i++)
		a[i]=read();
	q[0]=n+1;
	for(int i=n;i>=1;i--)
	{
		while(head<=tail && q[head]-i>m) head++;
		dp[i]=dp[q[head]]*k+a[i];
		while(head<=tail && dp[q[tail]]<=dp[i]) tail--;
		q[++tail]=i;
	}
	for(int i=1;i<=m;i++)
		ans=max(ans,dp[i]);
	printf("%.2lf",ans);
}

电压

一、题目

在这里插入图片描述

二、解法

我以前竟然做过类似的题,考试的时候还是蒙了。
考虑如果图是一颗树的话,那么条边都是可以选的,我们先建一颗生成树,再考虑向树上加入边,就会生成一个奇环和偶环,发现奇环上的边都是可选的,偶环上的边都是不可选的,这个可以用树上差分解决。
继续考虑两个非树边组合在一起的情况,我搞了一个图:
在这里插入图片描述
可以发现虽然两条数边生成了一个奇环,但这个奇环不会对答案造成影响(因为答案只会在第一个奇环中取),还有一些情况,读者可以手膜一下。
这样这道题就大概做出来了,还有几个特殊情况:
1、如果图不连通,在多个生成树中至多有1颗树有奇环。
2、如果某棵树只有一个奇环,那个生成奇环的非树边也可以作为一种答案。
??

#include <cstdio>
#include <vector>
using namespace std;
const int MAXN = 100005;
int read()
{
    int num=0,flag=1;
    char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int n,m,ans,all[MAXN],cnt,tot,p[MAXN],f[MAXN];
int c[MAXN],dep[MAXN],fa[MAXN][20];
struct edge
{
	int v,next;
}e[2*MAXN];
struct node
{
	int a,b;
}g[2*MAXN];
int findSet(int x)
{
	if(x^p[x]) p[x]=findSet(p[x]);
	return p[x];
}
void dfs(int u,int par)
{
	fa[u][0]=par;
	dep[u]=dep[par]+1;
	for(int i=1;i<20;i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=f[u];i;i=e[i].next)
		if(e[i].v^par)
			dfs(e[i].v,u);
}
int get(int u,int v)
{
	for(int i=19;i>=0;i--)
	{
		if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
		if(dep[fa[v][i]]>=dep[u]) v=fa[v][i];
	}
	if(u==v) return u;
	for(int i=19;i>=0;i--)
	{
		if(fa[u][i]!=fa[v][i])
			u=fa[u][i],v=fa[v][i];
	}
	return fa[u][0];
}
void cal(int u)
{
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==fa[u][0]) continue;
		cal(v);
		c[u]+=c[v];
	}
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
		p[i]=i;
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		int x=findSet(u),y=findSet(v);
		if(x==y)
		{
			g[++cnt]=node{u,v};
			continue;
		}
		p[x]=y;
		e[++tot]=edge{u,f[v]},f[v]=tot;
		e[++tot]=edge{v,f[u]},f[u]=tot;
	}
	for(int i=1;i<=n;i++)
		if(i==findSet(i))
			dfs(i,0);
	for(int i=1;i<=cnt;i++)
	{
		int u=g[i].a,v=g[i].b;
		int lca=get(u,v),t=dep[u]+dep[v]-2*dep[lca];
		if(t%2==0)
		{
			c[u]++;c[v]++;
			c[lca]-=2;
			all[findSet(u)]++;
		}
		else
		{
			c[u]--;c[v]--;
			c[lca]+=2;
		}
	}
	int cot=0;
	for(int i=1;i<=n;i++)
        if(all[i])
            cot++;
    if(cot>1)
    {
        puts("0");
        return 0;
    }
	for(int i=1;i<=n;i++)
		if(i==findSet(i))
			cal(i);
    for(int i=1;i<=n;i++)
        if(all[i]==1)
            ans++;
	for(int i=1;i<=n;i++)
		if(i!=findSet(i) && (all[findSet(i)] || !cot))
            ans+=(c[i]==all[findSet(i)]);
	printf("%d\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于微信小程序的家政服务预约系统采用PHP语言和微信小程序技术,数据库采用Mysql,运行软件为微信开发者工具。本系统实现了管理员和客户、员工三个角色的功能。管理员的功能为客户管理、员工管理、家政服务管理、服务预约管理、员工风采管理、客户需求管理、接单管理等。客户的功能为查看家政服务进行预约和发布自己的需求以及管理预约信息和接单信息等。员工可以查看预约信息和进行接单。本系统实现了网上预约家政服务的流程化管理,可以帮助工作人员的管理工作和帮助客户查询家政服务的相关信息,改变了客户找家政服务的方式,提高了预约家政服务的效率。 本系统是针对网上预约家政服务开发的工作管理系统,包括到所有的工作内容。可以使网上预约家政服务的工作合理化和流程化。本系统包括手机端设计和电脑端设计,有界面和数据库。本系统的使用角色分为管理员和客户、员工三个身份。管理员可以管理系统里的所有信息。员工可以发布服务信息和查询客户的需求进行接单。客户可以发布需求和预约家政服务以及管理预约信息、接单信息。 本功能可以实现家政服务信息的查询和删除,管理员添加家政服务信息功能填写正确的信息就可以实现家政服务信息的添加,点击家政服务信息管理功能可以看到基于微信小程序的家政服务预约系统里所有家政服务的信息,在添加家政服务信息的界面里需要填写标题信息,当信息填写不正确就会造成家政服务信息添加失败。员工风采信息可以使客户更好的了解员工。员工风采信息管理的流程为,管理员点击员工风采信息管理功能,查看员工风采信息,点击员工风采信息添加功能,输入员工风采信息然后点击提交按钮就可以完成员工风采信息的添加。客户需求信息关系着客户的家政服务预约,管理员可以查询和修改客户需求信息,还可以查看客户需求的添加时间。接单信息属于本系统里的核心数据,管理员可以对接单的信息进行查询。本功能设计的目的可以使家政服务进行及时的安排。管理员可以查询员工信息,可以进行修改删除。 客户可以查看自己的预约和修改自己的资料并发布需求以及管理接单信息等。 在首页里可以看到管理员添加和管理的信息,客户可以在首页里进行家政服务的预约和公司介绍信息的了解。 员工可以查询客户需求进行接单以及管理家政服务信息和留言信息、收藏信息等。
数字社区解决方案是一套综合性的系统,旨在通过新基建实现社区的数字化转型,打通智慧城市建设的"最后一公里"。该方案以国家政策为背景,响应了国务院、公安部和中央政法会议的号召,强调了社会治安防控体系的建设以及社区治理创新的重要性。 该方案的建设标准由中央综治办牵头,采用"9+X"模式,通过信息采集、案(事)件流转等手段,实现五信息中心的互联互通,提升综治工作的可预见性、精确性和高效性。然而,当前社区面临信息化管理手段不足、安全隐患、人员动向难以掌握和数据资源融合难等问题。 为了解决这些问题,数字社区建设目标提出了"通-治-服"的治理理念,通过街道社区、区政府、公安部门和居民的共同努力,实现社区的平安、幸福和便捷。建设思路围绕"3+N"模式,即人工智能、物联网和数据资源,结合态势感知、业务分析和指挥调度,构建起一个全面的数据支持系统。 数字社区的治理体系通过"一张图"实现社区内各维度的综合态势可视化,"一套表"进行业务分析,"一张网"完成指挥调度。这些工具共同提升了社区治理的智能化和效率。同时,数字社区还提供了包括智慧通行、智慧环保、居家养老和便民服务等在内的多样化数字服务,旨在提升居民的生活质量。 在硬件方面,数字社区拥有IOT物联网边缘网关盒子和AI边缘分析盒子,这些设备能够快速集成老旧小区的物联设备,实现传统摄像设备的智能化改造。平台优势体现在数字化能力中台和多样化的应用,支持云、边、端的协同工作,实现模块化集成。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值