补题日记(1)

一、洛谷P2392 kkksc03考前临时抱佛脚 (动态规划 ,01背包问题)

传送门P2392 kkksc03考前临时抱佛脚 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

首先呢,在这道题当中我们可以在每一科当中使用左右脑学习。

1、假设一科的总时间是8,那么左脑4,右脑4,只需要4的时间

2、假设一科总时间是9 ,左脑4,右脑5的话,需要5的时间

那么我们只看一个脑子,设成dp数组,他越接近总时间的一半,所需要的时间就越小,因为奇数的取整问题,最小时间就可以表示为 总 - dp[sum / 2];

以下请看AC代码


#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;
int a[4]  , h[40];
int t;
int dp[N];
int main(){
	for(int i =1;i<=4;++i)cin>>a[i];
	
	for(int i =1;i<=4;++i){
		int sum =0;
		for(int j =1;j<=a[i];++j){
			cin>>h[j];
			sum +=h[j];
		}
		
		for(int k =1;k<=a[i];++k){
			for(int l = sum/2;l>=h[k];--l){
				dp[l] = max(dp[l] , dp[l -h[k]]+h[k]);
			}
		}
		t +=sum - dp[sum/2];
		for(int q =1;q<=sum/2;++q)dp[q] =0;
	}
	cout<<t;
	return 0;
}

​

 

 二、洛谷P1002 [NOIP2002 普及组] 过河卒(动态规划)

传送门P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

首先马走日,我们可以定义两个方向向量

 

const int dx[] = {2,1,-1,-2,-1,-2,1,2} , dy[]= {1,2,2,1,-2,-1,-2,-1};

定义布尔类型vis数组判断马所在地,如果有就为true;

for(int i=0;i<8;++i){
		int tx = a+dx[i] , ty = b + dy[i];
		if(tx < 0 || tx >n || ty < 0 || ty > n)continue;
		vis[tx][ty] = true;
	}

对第0行和第0列进行初始化

	for(int i = 0;i<=m && vis[0][i] != true;++i)dp[0][i] = 1;
	for(int i =0;i<=n && vis[i][0] != true;++i)dp[i][0] = 1;

下面是AC代码,注意dp开long long

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N = 25;
bool vis[N][N];
ll dp[N][N];
int n,m,a,b;
const int dx[] = {2,1,-1,-2,-1,-2,1,2} , dy[]= {1,2,2,1,-2,-1,-2,-1};
int main(){
	cin>>n>>m>>a>>b;
	vis[a][b] =true;
	for(int i=0;i<8;++i){
		int tx = a+dx[i] , ty = b + dy[i];
		if(tx < 0 || tx >n || ty < 0 || ty > n)continue;
		vis[tx][ty] = true;
	}
	//初始化dp数组 
	
	for(int i = 0;i<=m && vis[0][i] != true;++i)dp[0][i] = 1;
	for(int i =0;i<=n && vis[i][0] != true;++i)dp[i][0] = 1;
	
	for(int i =1;i<=n;++i){
		for(int j =1;j<=m;++j){
			if(!vis[i][j]){
				dp[i][j] = dp[i-1][j] + dp[i][j-1];
			}
		}
	}
	cout<<dp[n][m];
	return 0;
}

三、洛谷P1031 [NOIP2002 提高组] 均分纸牌

传送门P1031 [NOIP2002 提高组] 均分纸牌 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

当全部相等后,每一堆纸牌的数量必然为平均数,由题意是平均数可以整除的

当前面一堆纸牌少于平均数时,就从后面的纸牌拿,不用担心后面的纸牌被拿走后是否会为负数,

因为总的纸牌数量是不会减少的总会有多的纸牌给他,所以我们不用关心中间的过程是否为变成负数

那么就有一下的AC代码

#include <bits/stdc++.h>
using namespace std;
int n , ans;
const int N = 105;
int a[N];
int main(){
	cin>>n;
	for(int i =1;i<=n;++i)cin>>a[i];
	int sum = 0;
	for(int i=1;i<=n;++i)sum +=a[i];
	int avg = sum / n;
	for(int i =1;i<n;++i){
		if(a[i] < avg){
			int t = avg -a[i];
			a[i] +=t;
			a[i+1] -= t;
			ans++;
		}
		else if(a[i] > avg){
			int t =a[i] -avg;
			a[i] -=t;
			a[i+1] += t;
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

四、牛客周赛 小红的回文串构造

传送门小红的回文串构造 (nowcoder.com)

比赛时候的方法比较麻烦,又写了一个简便的方法

假设一串数bbacabb ,我们不看中间的 就是abb bba我们看前面一节  bba b和b相同,就跳过,第二个b和a不同,换位置,此时再把后面对应的ab换位置就变成了babcbab一个新的字符串

那么bbbcbbb,前面一节 bbb三个数相同,无法换位置,所以就不会构成新的回文串

#include <bits/stdc++.h>
using namespace std;
int main(){
	string s;
    cin>>s;
    int n = s.length();
    for(int i=1;i<n/2;++i){
        if(s[i] !=s[i-1]){
            swap(s[i] , s[i-1]);
            swap(s[n-1-i] ,s[n-i]);
            
            cout<<s;
            return 0;
        }
    }
	cout<<-1;
	return 0;
}

五、牛客周赛 小红的整数操作

传送门小红的整数操作 (nowcoder.com)

我们可以通过gcd找到两者的最大公因数,让a,b分别除最大公因数,找到最小值。

让 右边界  ÷  最小值中较大的数 下取整

再让 左边界 ÷ 最小值中较小的数 上取整 

二者相减+1 则为答案,但注意有可能为负数所以和0取大

#include <bits/stdc++.h>
using namespace std;
int main(){
	int a,b,l,r;
    cin>>a>>b>>l>>r;
    if(a > b)swap(a,b);
    //此时a就是较小值
    int g = gcd(a,b);
    a /= g , b /= g;
    
    int x = r/b;
    int y =l / a + (l % a != 0); //上取整
    
    cout<<max(0 , x-y+1);
    
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值