codefores刷题心得3 思维+dp(特别好玩)
1.1438 C. Engineer Artem(思维)
我当时不会看的题解,很自闭,没想到今天看dalao,他也没想到,hhhhhh
题目链接:https://codeforces.com/contest/1438/problem/C
题目大意:给你一个数字矩阵,你可以选择任意位置+1操作(最多加一次),让你左右相邻和上下相邻的数字都不相同。
解题思路:
这题上下左右不可以相同,但是斜着的都是可以相同的。就可以把矩阵分成两块,只需要保证一块为奇数,另一块为偶数即可。就一定不会相同的。
这道题的题解太巧了呀!!!我什么时候能有这样的好脑子
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e2+4;
int mp[maxn][maxn];
int main(){
int t;
cin>>t;
int n,m;
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>mp[i][j];
if((i+j)%2==0){
if(mp[i][j]%2!=0){
mp[i][j]++;
}
}else{
if(mp[i][j]%2==0){
mp[i][j]++;
}
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
cout<<mp[i][j]<<' ';
cout<<endl;
}
}
return 0;
}
2.1389 B. Array Walk
dalao眼中的简单dp
题目链接:https://codeforces.com/contest/1389/problem/B
题目大意:从第一个位置进行移动,每次可向左或者向右移动,数组大小为n,移动次数为k,最多向左移动次数为z,让你求移动得到的最大的加和。
样例解释:
第一个只能向右移动: 1+5+4+3+2=15
第二个能向左移动一次: 1 +5+4+5+3=19
.....
所以可以使用dp操作,因为z<=5所以最多一次操作有5个可能的位置。
dp[i][j] //i代表第几次操作,j代表当前在哪个位置
dp[1][2]=a[1]+a[2]//经过一次操作,不可能在1的位置
dp[2][3]=dp[1][2]+a[3]
dp[2][1]=dp[1][2]+a[1]
dp[3][4]=dp[2][3]+a[4]
dp[3][2]=dp[2][3]+a[2]
dp[4][5]=dp[3][4]+a[5]
dp[4][3]=dp[3][2]+a[3],dp[3][4]+a[3]
dp[4][1]=dp[3][2]+a[1]
dp[5][6]=dp[4][5]+a[6]
dp[5][4]=dp[4][3]+a[4],dp[4][5]+a[4]
dp[5][2]=dp[4][3]+a[2],dp[4][1]+a[2]
但是n是1e5的数据大小,不能开这么大,可以开到dp maxn 10,10代表的是左移的次数,一次左移,两个位置,因为只能是左移和右移,所以岔开的是两个位数。5次两个位数,第i次操作就是i,i - 2,
i - 4 , i - 6,i - 8
#include <iostream>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int dp[maxn][10];//第二个是当前向左移动的次数
int main(){
int t,n,k,z;
cin>>t;
while(t--){
cin>>n>>k>>z;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=k+1;i++){
for(int j=0;j<=z;j++){
if(j==0) dp[i][0]=dp[i-1][0]+a[i];
else{//一个j代表两个位置。
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]);
dp[i][j]+=a[i-j*2];
}
}
}
int ans=0;
for(int i=0;i<=z;i++){
ans=max(ans,dp[k+1][i]);
}
cout<<ans<<endl;
}
return 0;
}