A. Regular Bracket Sequence
分析:普通的括号序列问题,判断一下左右括号数量是否相等,和任意前缀的左括号数量大于右括号就可以了。
#include <bits/stdc++.h>
using namespace std;
int main(){
long long a,b,c,d;
cin>>a>>b>>c>>d;
long long ans1=0,ans2=0;
ans1 = a*2 + b + c;
ans2 = b + c + d*2;
int ans = ans1==ans2;
if(c!=0 && (a==0||d==0))ans=0;
printf("%d\n",ans);
}
B. Discounts
分析:相当于每次选第一个第k贵的for free。
#include <bits/stdc++.h>
using namespace std;
long long a[300004];
int main() {
int n;
cin >> n;
a[0] = 0;
long long sum = 0;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
sum += a[i];
}
sort(a + 1, a + 1 + n);
/* for (int i = 1; i <= n; ++i) {
a[i]+=a[i-1];
}*/
int m;
cin >> m;
while (m--) {
int x;
scanf("%d", &x);
printf("%lld\n", sum - a[n - x + 1]);
}
}
C. Painting the Fence
分析:用bit维护覆盖次数为1和为2的点。枚举不用的两个不用的区间,计算非重叠区间内1和重叠区间内2的个数,用总的减去就可以了。
#include <bits/stdc++.h>
using namespace std;
struct BIT {
int n;
vector<int> v;
BIT(int n) : n(n) {
v.resize(n + 1);
}
void update(long long x, long long d) {
while (x <= n) {
v[x] += d;
x += (x & -x);
}
}
long long que(long long x) {
long long res = 0;
while (x > 0) {
res += v[x];
x -= (x & -x);
}
return res;
}
};
BIT bit1(5004), bit2(5004);
int a[5004];
int l[5004], r[5004];
int main() {
int n, m;
cin >> n >> m;
memset(a, 0, sizeof(a));
for (int i = 1; i <= m; ++i) {
cin >> l[i] >> r[i];
a[l[i]]++;
a[r[i] + 1]--;
}
int sum = 0;
int cnt = 0;
for (int i = 1; i <= n; ++i) {
sum += a[i];
a[i] = sum;
if (a[i] != 0)cnt++;
if (a[i] == 1)bit1.update(i, 1);
if (a[i] == 2)bit2.update(i, 1);
}
int ans = 0;
for (int i = 1; i <= m; ++i) {
for (int j = i + 1; j <= m; ++j) {
pair<int, int> p[2];
p[0] = {l[i], r[i]};
p[1] = {l[j], r[j]};
sort(p, p + 2);
int x = bit1.que(max(p[0].first,min(p[0].second, p[1].first))) - bit1.que(min(p[0].first,min(p[0].second, p[1].first)) - 1);
x += bit1.que(max(p[1].second,max(p[0].second, p[1].first) )) - bit1.que(min(p[1].second,max(p[0].second, p[1].first) ) - 1);
if (p[1].first <= p[0].second)x += bit2.que(min(p[0].second,p[1].second)) - bit2.que(max(p[1].first,p[0].first) - 1);
ans = max(ans, cnt - x);
}
}
cout << ans << endl;
}
D. Stressful Training
分析:单调性显而易见,可以考虑二分,问题在于如何check。
我们知道,每个时刻只能给一台电脑充电,那么此时肯定给最需要充电的电脑充电,这个量化一下就可以变成电量变为负数的时刻。那么我们每个时刻只需要找最早电用完的电脑充电就可以了,用优先队列很容易维护。注意常数不要太大。。
#include "bits/stdc++.h"
using namespace std;
long long a[200004];
long long b[200004];
long long n,k;
struct node
{
long long now,b,time;
bool friend operator < (node a,node b){
return a.time > b.time;
}
};
bool che(long long mid){
priority_queue<node>q;
for (int i = 1; i <= n; ++i) {
q.push({a[i],b[i],(a[i]+b[i])/b[i]});
}
int now = 1;
while(!q.empty() && now <= k){
node t = q.top();q.pop();
if(t.time < now)return 0;
now++;
t.now+=mid;
t.time = (t.now+t.b)/t.b;
if(t.time<=k)
q.push(t);
}
return 1;
}
int main(){
cin>>n>>k;
for (int i = 1; i <= n; ++i) {
scanf("%lld",&a[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%lld",&b[i]);
}
long long l = 0,r=1e15;
long long ans = -1;
while(l<=r){
long long mid = (l+r)>>1;
if(che(mid)){
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
cout<<ans<<endl;
}
E. Knapsack
分析:暴力搜,每个cnt最多搜8次就够了,证明略。
#include "bits/stdc++.h"
using namespace std;
long long num[10];
long long ans;
long long w;
void dfs(long long pos,long long sum){
if (pos==9)ans = max(ans,sum);
else {
long long maxi = min(num[pos],(w-sum)/pos);
for (long long i = maxi; i >=maxi-7 && i >= 0; --i) {
dfs(pos+1,sum + i * pos);
}
}
}
int main() {
cin >> w;
for (int i = 1; i <= 8; ++i) {
cin >> num[i];
}
ans = 0;
dfs(1,0);
cout<<ans<<endl;
}
F. Clear the String
分析:明显的区间dp。
#include "bits/stdc++.h"
using namespace std;
int dp[504][504];
int main() {
int n;
string s;
cin>>n>>s;
for (int i = 0; i <= n; ++i) {
dp[i][i] = 1;
}
for (int len = 2; len <= n; ++len) {
for (int i = 1; i + len - 1 <= n; ++i) {
int j = i + len - 1;
dp[i][j] = dp[i][j-1]+1;
for (int k = i; k <= j - 1; ++k) {
if(s[j-1]==s[k-1])
dp[i][j]=min(dp[i][j],dp[i][k] + dp[k+1][j-1]);
}
}
}
cout<<dp[1][n]<<endl;
}