A-Domino on Windowsill
从k1和k2里面找个小的,前面可以竖着放,后面只能横着放,后面黑色的同理,然后判断一下即可。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e4 + 10;
int main() {
int T;scanf("%d",&T);
int n,w,b,k1,k2;
while(T--) {
scanf("%d%d%d",&n,&k1,&k2);
scanf("%d%d",&w,&b);
int fg = 0;
int min_pre = min(k1,k2);
min_pre += (max(k1,k2) - min(k1,k2)) / 2;
int min_suf = min(n-k1,n-k2);
min_suf += (max(n-k1,n-k2) - min(n-k1,n-k2)) / 2;
if(min_pre < w || min_suf < b) fg = 1;
if(fg) puts("NO");
else puts("YES");
}
return 0;
}
B-Binary Removals
题意:给你一长度s的01串然后让你删除其中一些两两都不连续的位置,使得这个串达到有序的状态,问你能否实现。
思路:
假如碰到了10这种情况我们有两种删法,删去前面的1和后面的0。
我们优先选择的是去删掉前面的1,因为0后面可以放0或者1,但1后面只能放1,所以我们留着0肯定是更好的,但是如果110这种情况我就不能删1,只能去删0但如果又是1100这种情况,那么我们就不能删0,此时就不可能把它变有序了。
所以我们只需要判断一个0前面是否有两个及以上连续的1或者他后面是不是0即可,删去的字符会不会影响后面呢,我们是否需要修改,删1的话我们就把1的位置变成0,删0的话我们就把0的位置变成1,这样就不会对后面有影响了。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 100 + 10;
char s[N];
int main() {
int T;scanf("%d",&T);
while(T--) {
scanf("%s",s+1);
int n = strlen(s + 1);
int fg = 0,cnt1 = 0;
for(int i = 1;i < n; ) {
s[i] == '1' ? cnt1++ : cnt1 = max(0,cnt1-1);//注意细节别笨比
if(s[i] < s[i-1]) {
if(!cnt1) {
s[i-1] = '0';
i++;
}
else if(s[i+1] > s[i]) {
s[i] = '1';
i++;
}
else { fg = 1; break; }
}
else {
i ++;
}
}
if(fg) puts("NO");
else puts("YES");
}
return 0;
}
C-Minimum Grid Path
题意:
你从(0,0)出发到达(n,n)点,你只能选择往上走或者往右走,并且转向的次数不可以超过n-1,也就是你的路线最多是由n条线段组成的,然后会给定你第i条线段的花费c[i]问你怎样才能使得到达终点的花费最少。
思路:
主要这里c数组是给定好的,顺序不能变,可以想到我们需要留出找出两条花费最少的线段使得其走的步数尽可能的多,由于是到(n,n)点我们先往右或者先往上其实是等效的,所以我们当前步数的奇偶性来定义走的方向。
但是并不是找到两个方向上的最小值就行,因为你不知道最小值比次小值小的那部分值会不会被多走的几步给加回来边的更大,所以我们枚举走的步数,维护一个走到当前位置时,两个方向上的最小值分别是多少,很明显,在两个方向上其他线段我们就只分配一步,剩下的都有当前的最小走完。
这样就是再维护一下前缀和,然后O(1)的就算出当前答案了,最后n步里取个min就是我们的最小花费。
还是要多想多思考题目的条件能怎么巧妙的转化,例如这就是就是把两个方向变成了奇偶去讨论,因为奇偶性改变一次就可以看做方向改变一次。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;
int n;
ll c[N],sum[N];
int main() {
int T;scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(int i = 1;i <= n;i ++) {
scanf("%lld",&c[i]);
sum[i] = sum[i-1] + c[i];
}
ll odd = INF,even = INF,ans = INF;
// cout << odd << ' ' << even << ' ' << ans << '\n';
//用奇偶来区分方向 只需要在每一步贪心的让当前最小的那个数尽可能夺走即可
for(int i = 1;i <= n;i ++) {//
if(i & 1) odd = min(odd,c[i]);
else even = min(even,c[i]);
ll res = 0;
if(i < 2) continue;
if(i & 1) {
res = sum[i];
res += (n - i / 2 - 1) * odd;
res += (n - i / 2) * even;
}
else {
res = sum[i];
res += (n - i / 2) * odd;
res += (n - i /2 ) * even;
}
ans = min(ans,res);
}
printf("%lld\n",ans);
}
return 0;
}