[2021-3-12]BNUZ套题比赛div3(重开)

52 篇文章 1 订阅
34 篇文章 0 订阅

A题:
解题思路:
分两种情况
1.n小于k的情况,那么就是要把k平均分成n份,如果说不能平均分,那么就有一份会多出1(不可能多出2,因为余数是2的话那么就被其他的份接收了,即此时最大值有两个).
2.n大于k的情况,让k大于n( 即k=k*(n/k) )就可以了,变成上面的情况
代码:

#include<iostream>
using namespace std;
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, k;
		cin >> n >> k;
		int temp = k % n  ? 1 : 0;
		if (n > k) {
			temp = n % k ? 1 : 0;
			k = k * ((n / k) + temp);
		}
		int ans = k / n;
		cout << ans + temp << endl;
	}
}

B题(别人的题解):
既然是前缀和的占比,并且第一个是 a[1] 没有前缀和,那么我们把所有增加量都放在 a[1] 即可。
从左往右遍历,找到不符合条件的数,并用其增加量来更新答案取最大值就好。

#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
ll a[200001], b[200001];
ll max(ll a1, ll a2) {
	return a1 > a2 ? a1 : a2;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		ll ans = 0 , n, k;
		cin >> n >> k;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			b[i] = b[i - 1] + a[i];
		}
		for (int i = 2; i <= n; i++) {
			ll temp = 100 * a[i] - b[i - 1] * k ;
			if (temp > 0) { ans = max(ans, temp); }
		}
		cout << ans / k + (ans % k ? 1 : 0) << endl;
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
	}
}

C题(别人的题解):
链接:https://blog.csdn.net/weixin_45750972/article/details/113439070
题意
​ 给定n条链,每条链有ci个点,给定第i条链的首尾点与前一条链相连的关系,求最长简单环长度
贪心,显然答案肯定是一段连续的链区间,我们只需考虑对于当前第i ii条链,如果作为起点更优就更新,否则就充当中间链,注意特判下首尾点连向相同点的情况,这种情况必须截断,重新设置起点。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
int t,n,a[N],b[N],c[N]; 
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&c[i]);
		ll ans=0;
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(int i=1;i<=n;i++) scanf("%d",&b[i]);
		ll x=a[2],y=b[2];
		ll tmp=abs(x-y)+2;
		for(int i=2;i<n;i++){
			if(a[i+1]==b[i+1]){
				ans=max(ans,tmp+c[i]-1);
				tmp=2;
			}
			else {
				ans=max(ans,tmp+c[i]-1);
				if(tmp+c[i]-1-abs(a[i+1]-b[i+1])<abs(a[i+1]-b[i+1])) tmp=abs(a[i+1]-b[i+1])+2;
				else tmp=tmp-1+c[i]-abs(a[i+1]-b[i+1])+2;
			}
		}
		tmp=tmp+c[n]-1;
		printf("%lld\n",max(tmp,ans));
	} 
	return 0;
}

D题:
由题目可知:既然要让这个前后缀小于k(即让字符串的前后缀最小),那么我们就直接abcabcab…那样就前后缀为0即小于k.
代码:

#include<iostream>
#include<string>
using namespace std;
string a;
int  main() {
	int T;
	scanf("%d",&T);
	while (T--) {
		int n, k;
		cin >> n >> k;
		for (int i = 0; i < n; i++) {
			printf("%c",'a'+i%3);
		}
		printf("\n");
	}
	return 0;
}

E题:
解题思路:
两种方法:
1.先找形状为.的树,再找形状为.^,的树,以此类推,但是时间复杂度很高,不是好的算法
TLE代码如下:

#include<iostream>
#include<cstring>
using namespace std;
char a[500][500];
int dy[] = { 0,-1,1 };
int n, m, ans;
int zz = 0;
void find(int x, int y, int k)
{
	//cout << "x=" << x << "y=" << y << endl;
	int tx,ty;
	if (k <= 0) {  return; }
	for (int i = 0; i < 3; i++) {
		tx = x + 1;
		ty = y + dy[i];
		if (tx < 0 || tx >= n || ty >= m) {
			zz = -1; return;
		}
		if (a[tx][ty] != '*') { zz = -1; return; }
	}
	for (int i = 0; i < 3; i++) {
		tx = x + 1;
		ty = y + dy[i];
		find(tx, ty, k - 1);
	}
	return;
}
void dfs(int step)
{
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if(a[i][j]=='*') {
			zz = 0;
			find(i, j, step);
			if (zz == 0)ans++;
		}
		}
	}
	return;
}
int  main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;
		for (int i = 0; i < n; i++) { 
			cin >> a[i];
		}
		for (int i = 0; i < n; i++) {
			dfs(i);
		}
		cout << ans << endl;
		ans = 0;
	}
	return 0;
}

方法2:
从下往上找,找到为’*'的点,就让这个点对应的值为1加上下面三个格子的值其中的最小值:

#include<iostream>
#include<cstring>
using namespace std;
int n, m, v[600][600];
char a[601][601];
long long ans;
int min(int a1, int a2) {
	return a1 < a2 ? a1 : a2;
}
int min(int a1, int a2, int a3) {
	return a1 < min(a2, a3) ? a1 : min(a2, a3);
}
void func1()
{
	int i, j;
	for (i = n-1; i >= 0; i--) {
		for (j = 0; j < m; j++) {
			if (a[i][j] == '*') {
				v[i][j] = 1;
				 v[i][j] += min(v[i + 1][j], v[i + 1][j - 1], v[i + 1][j + 1]);
				//cout << "i=" << i << ",j=" << j << ",v[i][j]="<<v[i][j]<<endl;
			}
		}
	}
}
void func2()
{
	int i, j;
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			ans += v[i][j];
		}
	}
}
int main()
{
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;
		for (int i = 0; i < n; i++)cin >> a[i];
		func1();
		func2();
		cout << ans << endl;
		ans = 0;
		memset(v, 0, sizeof(v));
		memset(a, 0, sizeof(a));
	}
	
}

F题(别人的题解):
思路:
对于后缀序ai,ai+1,…,an如果该序列已经全部满足ai=i,那么对于任意的r∈[i,n],他们是否排序都不会影响最终答案。但是如果不是这种序列就必须保证最后一个ai!=i必须有r=i,并且进行概率为p的操作。而后面的操作是否进行实际上都不影响答案,如果不进行刚才的操作,就必须保证r>i的操作至少进行一次。因此答案需要累加r>i的每钟操作一次。特判一下整个序列都已经从小到大排好的情况,此时答案为1.

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
int T,n,m,a[maxn];
struct Node{
	int f;double q;
}t[maxn];
int cmp(Node x,Node y){
	return x.f<y.f;
}
int main(){
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1;i<=n;i++)cin>>a[i];
		for(int i=1;i<=m;i++)cin>>t[i].f>>t[i].q;
		sort(t+1,t+1+m,cmp);
		int s=0;
		for(int i=n;i>=1;i--){
			if(a[i]!=i){
				s=i;
				break;
			} 
		}
		double ans=0,sum=1.0;
		for(int i=m;i>=1;i--){
			if(t[i].f>=s){
				ans=ans+sum*t[i].q;
				sum*=(1-t[i].q);
			}
			else{
				break;
			}
		}
		if(s==0)ans=1.0;
		printf("%.7lf\n",ans);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值