2022“杭电杯”中国大学生算法设计超级联赛(8)(1,4,8,11)

第1题

部落的战舰可以被描述为一根弦ss它只包含“0”和“1”,表示小型战舰和大型战舰。Jaina可以对琴弦进行一些魔术表演。在一个魔法中,她选择一个具有奇数长度的任意间隔并将其反转。Jaina可以随心所欲地表演这种魔法。Jaina希望小型战舰在前线,因为它们更容易被摧毁。她向你寻求帮助,你需要告诉她她能得到的最小的字典。

就是字符串翻转问题,不过要求只可以翻转奇数个,并且求最小字典数。因为选择的是奇数长度,所以每个 01 的奇偶性是不变的,最小就是奇数和偶数位置的 1 分别移动到最后面。借助这个特点很快就可以做出来。

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+7;

void solve(){
	char s[N];
	int ans[N];
	scanf("%s",s);
	int len=strlen(s);
	int j0=0,j1=0,o0=0,o1=0;
	for(int i=1;i<=len;i++){
		if(i%2==1&&s[i-1]=='0')j0++;
		else if(i%2==1&&s[i-1]=='1')j1++;
		else if(i%2==0&&s[i-1]=='0')o0++;
		else if(i%2==0&&s[i-1]=='1')o1++;
	} 
	int j=1;
	while(j0--){
		ans[j]=0;
		j+=2;
	}
	while(j1--){
		ans[j]=1;
		j+=2;
	}
	j=2;
	while(o0--){
		ans[j]=0;
		j+=2;
	}
	while(o1--){
		ans[j]=1;
		j+=2;
	}
	for(int i=1;i<=len;i++)printf("%d",ans[i]);
	printf("\n");
}

int main(){
	int t;
	cin>>t;
	while(t--)solve();
}

第4题

Kael'thas有一个魔方,其中包含2D平面上的所有点,其坐标为整数[0,n].他可以在飞机上画几条直线。每条线将覆盖其上的所有点。请注意,这些线没有端点,并且在两个方向上都延伸到无穷大。还有一个特殊的规则:他不能画一条覆盖点的线。(0,0)因为他的宝座在(0,0)他需要绘制的最小线数是多少,以便这些线将覆盖魔方的所有点,除了(0,0)?

签到题,画个图直接过,答案就是2*n。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        cout<<2*n<<endl;
    }
}

第11题

瓦里安·瑞恩在战斗中获得了一块长方形的黄金,长度nn和宽度mm.现在他想在黄金上画一些线,这样以后他就可以沿着这条线切割黄金。他画的线条应满足以下要求:

  1. 线的端点应该在金的边界上。
  2. 这些线应至少平行于金的一个边界。
  3. 沿着所有线条切割后,每块金子都是一个长度和宽度为整数的矩形。
  4. 沿着所有线条切割后,每块黄金的面积至少应为kk.
  5. 两条线不应共享一个以上的共同点。

瓦里安·雷恩(Varian Wrynn)希望以一种最大化他绘制的线条的方式切割黄金。作为联盟的最高国王,他当然没有时间这样做。所以他找到了你!请帮他切金子!

就是求最多的刀数,明显保障长边取最大值,然后再补充另外一边。面积要大于等于k,所以尽量在同一方向上切是最优解,在另一边相切就会产生更多的小金块,面积就会更小。

#include<bits/stdc++.h>
using namespace std;
int n,m,k,t,p,ansn,ansm,ans,ln,lm;
long long int s;
int main()
{
	scanf("%d",&t);
	for (int i=1;i<=t;i++){
		scanf("%d%d%d",&n,&m,&k);
		for(int j=1;j<=n;j++){
			if (j*m>=k){
				ansn=floor(n/j)-1;
				ln=j;
				break;
			}
		}
		//cout<<ansn;
		for (int j=1;j<=m;j++){
			if ((floor(m/(j+1))*ln) >= k)
				continue;
			else
				{
					ansn=ansn+j-1;
					break;
				}
		}
	//	cout<<ansn<<endl;
		
			for(int j=1;j<=m;j++){
			if (j*n>=k){
				ansm=floor(m/j)-1;
				lm=j;
				break;
			}
		}
		for (int j=1;j<=n;j++){
			if (floor(n/(j+1))*lm>=k)
				continue;
			else
				{
					ansm=ansm+j-1;
					break;
				}
		}
		cout<<max(ansn,ansm)<<endl;
	}
	return 0;
} 

补题时间

第8题

无向图的解离集是一组顶点,如果我们只保留这些顶点之间的边,则集合中的每个顶点最多连接到一条边。解离集的大小由顶点集的大小定义。图的最大解离集由具有最大大小的图的解离集定义。西尔瓦纳斯有一个连接的无向图,该图具有以下nn顶点和n - 1边,她想找到图的最大解离集的大小。但既然她刚刚成为部落的战将,她就忙得无法解决问题。请帮助她这样做。

这道题目解离集的概念让我们思考了好久,搞明白之后也还是wa。看题解用树形dp写可以大致明白,但自己写出来还是比较难。这边是其他大佬的代码。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	cin >> n;
	vector < vector<LL> > e(n + 1);
	for (int i = 0; i < n - 1; i ++ ){
		LL u, v;
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	vector < array<LL, 3> > dp(n + 1);
	LL ans = 0;
	function<void(LL, LL)> dfs = [&](LL u, LL fa){
		dp[u][0] = 0;	//不选
		dp[u][1] = 1;	//起点
		dp[u][2] = 0;	//终点
		LL sum0 = 0, sum1 = 0;
		for (auto v : e[u]){
			if (v == fa) continue;
			dfs(v, u);
			sum0 += max(dp[v][0], max(dp[v][1], dp[v][2]));
			sum1 += dp[v][0];
		}
		dp[u][0] = max(dp[u][0], sum0);  //不选 u 的话,所有相连的节点不论什么状态都可以
		dp[u][1] = max(dp[u][1], sum1 + 1);  //选了 u 作为起点,那么所有相连的节点都不能选
		for (auto v : e[u]){  //找最大的方案
			if (v == fa) continue;
			dp[u][2] = max(dp[u][2], sum1 - dp[v][0] + dp[v][1] + 1);  //选 u 作为终点,那么要找一个起点
		}
		for (int i = 0; i < 3; i ++ )
			ans = max(ans, dp[u][i]);
	};
	dfs(1, 0);
	cout << ans << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int size(512<<20);
	__asm__ ( "movq %0, %%rsp\n"::"r"((char*)malloc(size)+size));
	LL T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	exit(0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值