HGOI-国庆七连测-day4

题解

今天这个题和昨天的题目完全不是一个水平的吗…orz今天这个打第三题的时间昨天还在打第一题…就不能两天的题目匀一下么…


第一题——吴翼的木棍(kusac)

【题目描述】

  • 给出n条长度为1的木棍,可以在任意位置进行切割,要求木棍平均分配给m个人的情况下切的刀数最少。

  • 感谢dasxxx大佬提供算法思路。
  • 可以算出,每个人平均分到 n m \frac{n}{m} mn的长度。
  • 可以把这些木棍接起来,然后你会发现每 n m \frac{n}{m} mn的地方来一刀效果最好。
  • 但是原本这些木棍是断开的,那么原来断开的地方和你要的切点重合的地方就不用动刀子,就要减去。
  • 原来要切m刀,但是会有 n ∗ m / l c m ( m , n ) n*m/lcm(m,n) nm/lcm(m,n)个空格是多出来的。

#include <iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
inline void fff(){
	freopen("kusac.in","r",stdin);
	freopen("kusac.out","w",stdout);
}
int n,m;
int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}
int lcm(int a,int b){int g=gcd(a,b);return a/g*b;}
int main(){
//	fff();
	scanf("%d%d",&n,&m);
	printf("%d",m-n*m/lcm(n,m));
	return 0;
}

第二题——吴翼的书(lopov)

【题目描述】

  • 给出 n n n本书,价值为 v i v_i vi,质量为 w i w_i wi
  • 给出 k k k个包,容量为 c i c_i ci,且一个包只能放一本书。
  • 求最大价值是多少。

  • 看上去像背包,但是其实是贪心。因为一个包只能放一本书,那么可以说在这个包的范围内装上他能装的最大的价值。
  • 那么就可以把包升序排一个序,然后把书按照质量也升序排序。然后质量比当前的包的容量小的书当中取出最大价值的。
  • 那就会用到堆来求得最小值。

#include <iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define LL long long
using namespace std;
inline void fff(){
	freopen("lopov.in","r",stdin);
	freopen("lopov.out","w",stdout);
}
const int N=301000;
inline LL read(){
	LL x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x;
}
LL n,k;
struct node{
	LL w,v;
	bool operator < (const node x) const{
		return v<x.v;
	}
}a[N];
LL c[N];
priority_queue <node> HEAP;
bool cmp1(node x1,node x2){
	return x1.w<x2.w;
}
LL ans=0;
int main(){
//	fff();
	n=read(),k=read();
	for(LL i=1;i<=n;i++) a[i].w=read(),a[i].v=read();
	for(LL i=1;i<=k;i++) c[i]=read();
	sort(c+1,c+k+1);
	sort(a+1,a+n+1,cmp1);
	int tt=1;
	for(LL i=1;i<=k;i++){
		while(a[tt].w<=c[i]&&tt<=n) HEAP.push(a[tt++]);
		if(HEAP.empty()) continue;
		node temp=HEAP.top();HEAP.pop();
		ans+=(LL)temp.v;
	}
	cout<<ans;
	return 0;
}

第三题——吴翼的矩阵(ratar)

【题目描述】

  • 有一个N*N 的矩阵,矩阵内元素大小 a i ∈ [ − 1000 , 1000 ] a_i\in [-1000,1000] ai[1000,1000]
  • 现在你要选两个子矩阵,满足:
    • 1.两个子矩阵内的元素之和恰好相等。
    • 2.两个子矩阵的边界(指的是矩形的边界,不是指边界的元素)恰好有一个公共点,并且不存在一个元素同时属于这两个子矩阵。
  • 求方案数。

  • 做法一:暴力枚举两个矩阵的左上右下节点求出和(前缀和),复杂度 O ( n 8 ) O(n^8) O(n8)
  • 做法二:发现会有一个节点是公共节点,可以减少枚举一个点 O ( n 6 ) O(n^6) O(n6)
  • 做法三。由于要求出和相等的矩阵,那么可以枚举固定点,然后枚举左上的矩阵,统计相同和的矩阵个数,再枚举右下矩阵的, a n s = ∑ n u m [ s u m ] ans=\sum num[sum] ans=num[sum]。复杂度就是降到了 O ( 6 ∗ n 4 ) O(6*n^4) O(6n4)

#include <iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
inline void fff(){
	freopen("ratar.in","r",stdin);
	freopen("ratar.out","w",stdout);
}
const int N=55;
const int MAXN=2500000;
int n;
int mp[N][N],sum[N][N];
int mmp[5000100];
vector <pair<point,point> > v[10000000];
inline int get_sum(int x1,int y1,int x2,int y2){
	return sum[x1][y1]+sum[x2-1][y2-1]-sum[x1][y2-1]-sum[x2-1][y1];
}
int ans=0;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&mp[i][j]);
	memset(sum,0,sizeof(sum));
	for(int x1=1;x1<=n;x1++)
		for(int y1=1;y1<=n;y1++)
			sum[x1][y1]=sum[x1-1][y1]+sum[x1][y1-1]-sum[x1-1][y1-1]+mp[x1][y1];
	int k=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			for(int x=1;x<=i;x++)
				for(int y=1;y<=j;y++)
					mmp[get_sum(i,j,x,y)+MAXN]++;
			for(int x=i+1;x<=n;x++)
				for(int y=j+1;y<=n;y++)
					ans+=mmp[get_sum(x,y,i+1,j+1)+MAXN];
			for(int x=1;x<=i;x++)
				for(int y=1;y<=j;y++)
					mmp[get_sum(i,j,x,y)+MAXN]--;
			for(int x=1;x<=i;x++)
				for(int y=j;y<=n;y++)
					mmp[get_sum(i,y,x,j)+MAXN]++;
			for(int x=i+1;x<=n;x++)
				for(int y=1;y<j;y++)
					ans+=mmp[get_sum(x,j-1,i+1,y)+MAXN];
			for(int x=1;x<=i;x++)
				for(int y=j;y<=n;y++)
					mmp[get_sum(i,y,x,j)+MAXN]--;
		}
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值