一起来做题~欢乐赛2
A 新比赛,在眼前。
拿到这个题,我们来看,给一个数x,再给一个字符
如果是+,说明我们的x大于了我们的答案,也就是我们的答案在x的左侧;如果是-,说明x小于我们的答案,也就是我们的答案在x的右侧。
如果是=,说明我们的x等于x。
那么,我们将他画到横轴上,就是区间,区间重复最多的就是我们的答案。
下面是做题思路。
我想的就是将信息存下来,然后排个序,然后离散化,但是和雨巨的map比较一下,逊爆了。
来,学习一下。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <climits>
#include <map>
using namespace std;
int n;
map<int, int> b;
int main()
{
cin >> n;
while (n -- )
{
int x; char op[2];
scanf("%d%s", &x, op);
//公式b[L] ++, bp[R + 1] --
if (*op == '+')
{
//当前结果大了,说明结果在左侧
b[0] ++;
b[x] --;//不包含当前数x
}
else if (*op == '-')
{
b[x + 1] ++;
b[INT_MAX] --;
}
else
{
b[x] ++;
b[x + 1] --;
}
}
int ans = 0, sum = 0;
for (auto it : b)
{
sum += it.second;
ans = max(ans, sum);
}
cout << ans << "\n";
return 0;
}
B 有人说,上周题还没做完……
线性DP,我们将给的数组用线性DP扫一下,将哪些能被用其他元素叠加所得得元素给标记一下,然后再查下表记个数就OK了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110, M = 25010;
int n;
int a[N];
int dp[M];
void work()
{
cin >> n;
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
}
memset(dp, -1, sizeof dp);
dp[0] = 0;
for (int i = 1; i <= n; i ++ )
for (int j = a[i]; j <= M - 10; j ++ )
{
if (dp[j-a[i]] >= 0) dp[j] = max(dp[j], dp[j - a[i]] + 1);
}
// for (int i = 1; i <= 100; i ++ )
// cout << dp[i] << ' ';
// cout << endl;
int cnt = 0;
for (int i = 1; i <= n; i ++ )
if (dp[a[i]] == 1) cnt ++;
cout << cnt << endl;
}
int main()
{
int T; cin >> T;
while (T -- )
{
work();
}
return 0;
}
C 要变强,不空喊,ak题目,继续向前。
题意:给定n个区间,我们可以从每个区间中选出一个数,将这些选出的数的平方加一起算个和,输出这些和的个数
看到这里,我们很明显的想到了这是一个分组背包问题,每组内只可以选择一个物品。按照分组背包的模板,我们要做的是第一维枚举组别,第二维枚举区间大小(100个数,每个数要平方,显然就是1e6大小的),第三位枚举背包内的物品。
f[i][j]
表示前i个数能否组成j这个数的意义,可以用bool来存。但是,我们发现,时间一定会超限,这里我们可以用bitset来存数组
#include <bits/stdc++.h>
using namespace std;
int n;
bitset<1010> f[110];
int main(void)
{
cin >> n;
f[0][0] = 1;
for (int i = 1; i <= n; i ++ )
{
int l, r; scanf("%d%d", &l, &r);
for (int k = l; k <= r; k ++ )
f[i] |= f[i - 1] << (k * k);
}
cout << f[n].count() << "\n";
return 0;
}