原题链接
给出一个数组a,把数组a中的元素分给两个空数组,要求第一个数组中的每个元素都不能是第二个数组中元素的倍数,输出一种分法
首先,对a排序,只要出现了1,一定是放在b数组里,否则放在c里,b中就一定会出现1的倍数
然后不是1的第一个元素一定要放在c中,因为要求bc都非空
之后因为数据范围比较小,就是暴力枚举了,这个数如果是c中元素的倍数就放到c,不是就放到b
#include
using namespace std;
using i64 = long long;
typedef pair<int, int> PII;
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
sort(a.begin(), a.end());
vector<int> b, c;
for (int i = 0; i < n; i ++ )
{
if (a[i] == 1 || a[i] == a[0])
{
b.push_back(a[i]);
continue;
}
if (c.empty())
{
c.push_back(a[i]);
continue;
}
int k = a[i];
bool flag = true;
for (int j = 0; j < c.size(); j ++ )
{
if (k % c[j] == 0)
{
c.push_back(k);
flag = false;
break;
}
}
if (flag) b.push_back(k);
}
if (b.empty() || c.empty()) cout << -1 << '\n';
else
{
cout << b.size() << ' ' << c.size() << '\n';
for (int i = 0; i < b.size(); i ++ ) cout << b[i] << ' ';
cout << '\n';
for (int i = 0; i < c.size(); i ++ ) cout << c[i] << ' ';
cout << '\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}
原题链接
给出多个数组,对于每个数组都可以将它其中的任意一个元素挪到另一个数组,问操作后的 【数组最小值之和】 最大是多少
这一题只和每个数组的最小的两个数有关,所以无需记录下全部元素
因为可以随便移动,我们发现,所有数组元素中最小的一个(后文叫它x)无论移到哪都是最小的,其他数组中最小的元素只要移到那个包含x的数组中,那个数组中最小的元素还是x,而其他数组中最小的元素都变成了原来第二小的元素
所以最大值就应该是所有数组中最小元素中的最小的元素加上所有数组中第二小元素之和删去第二小元素中最小的元素
另外要注意一下,如果只有一个数组,那只能输出该数组中最小的元素
#include
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
void solve()
{
int n;
cin >> n;
vector<int> b, c;
for (int i = 0; i < n; i ++ )
{
int m;
cin >> m;
vector<int> a(m);
for (int j = 0; j < m; j ++ ) cin >> a[j];
sort(a.begin(), a.end());
b.push_back(a[0]);
c.push_back(a[1]);
}
sort(c.begin(), c.end());
i64 sum = 0, cnt = 0;
for (int i = 0; i < n; i ++ )
{
sum += b[i];
if (i != 0) cnt += c[i];
}
sort(b.begin(), b.end());
cnt += b[0];
if (n == 1) cout << b[0];
else cout << cnt;
cout << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}
原题链接
排列表示一个长度为n的数组包含1-n这n个数字
现在给出n,要求一种排列使得 【所有位数乘该位上的元素之和】减去【位数乘该位上的元素之和的最大值】这个结果最大,输出最大值
先找到规律,发现所有最大值的情况都是后面一部分数组逆序,然后直接暴力枚举
#include
using namespace std;
using i64 = long long;
typedef pair<int, int> PII;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 0; i <= n; i ++ ) a[i] = i;
i64 ans = 0, maxx = 0, temp = 0;
for (int i = 0; i < n; i ++ )
{
temp = 0;
reverse(a.begin() + i + 1, a.end());
for (int j = 1; j <= n; j ++ )
{
maxx = max(maxx, (i64)(a[j] * j));
temp += a[j] * j;
}
ans = max(ans, (i64)(temp - maxx));
reverse(a.begin() + i + 1, a.end());
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}
原题链接
给出若干个组区间 l、r、a、b,在 l - r 中的点可以传到 a - b,现给出若干个起始点,求最终能传送到的离原点的最远位置是哪个
只需要关注 l b,因为在 b - r 中的点传送后最远只能到 b,因此就无需传送,只需要将所有 l - b 中的点传到 b 即可,进行区间合并,输入询问直接输出结果
#include
using namespace std;
typedef pair<int, int> PII;
void solve()
{
int n;
cin >> n;
vector<PII> trans(n);
for (int i = 0; i < n; i ++ )
{
int rr, aa;
cin >> trans[i].first >> rr >> aa >> trans[i].second;
}
sort(trans.begin(), trans.end());
vector<int> l, b;
for (int i = 0; i < n; )
{
int x = trans[i].first, y = trans[i].second;
while (i < n && trans[i].first <= y)
{
y = max(y, trans[i].second);
i ++ ;
}
l.push_back(x);
b.push_back(y);
}
int q;
cin >> q;
while (q -- )
{
int x;
cin >> x;
int k = upper_bound(l.begin(), l.end(), x) - l.begin() - 1;
if (k == -1 || b[k] <= x) cout << x << ' ';
else cout << b[k] << ' ';
}
cout << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}