一、洛谷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;
}
四、牛客周赛 小红的回文串构造
比赛时候的方法比较麻烦,又写了一个简便的方法
假设一串数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;
}
五、牛客周赛 小红的整数操作
我们可以通过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;
}