A
可知把最大的分配给a,从大到小分配n/2个元素给b,其余给a
int t; cin >> t;
while (t--)
{
int n; cin >> n;
ll ans1 = 0, ans2 = 0;
ans1 = 1 << n;
for (int i = n - 1; i >= n - n / 2; --i) {
ans2 += 1 << i;
}
for (int i = n - n / 2 - 1; i >= 1; --i) {
ans1 += 1 << i;
}
cout << ans1 - ans2 << endl;
}
B
构成循环节,分析可得出现数字种类多于k将无法构造
按照出现的数字,在原序列中补充即可
int a[maxn], vis[105];
vector<int> ans, pre;
int main()
{
int t; scanf("%d", &t);
while (t--) {
int n, k; scanf("%d%d", &n, &k);
memset(vis, 0, sizeof(vis)); pre.clear();
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
if (vis[a[i]]++ == 0) {
pre.push_back(a[i]);
}
}
if (pre.size() > k) {
printf("-1\n");
continue;
}
if (n == 1) {
printf("1\n1\n");
continue;
}
while (pre.size() < k) pre.push_back(1);
sort(pre.begin(), pre.end());
ans.clear();
for (int i = 1, last; i <= n; ++i) {
if (i == 1) {
for (int j = 0; j < k; ++j) {
ans.push_back(pre[j]);
if (pre[j] == a[i]) {
last = j + 1;
break;
}
}
}
else if (i != n) {
for (int j = last; j < k; ++j) {
ans.push_back(pre[j]);
}
for (int j = 0; j < k; ++j) {
ans.push_back(pre[j]);
if (pre[j] == a[i]) {
last = j + 1;
break;
}
}
}
else {
for (int j = last; j < k; ++j) {
ans.push_back(pre[j]);
}
for (int j = 0; j < k; ++j) {
ans.push_back(pre[j]);
}
}
}
printf("%d\n", ans.size());
for (int i = 0; i < ans.size(); ++i) {
if (i == ans.size() - 1) printf("%d\n", ans[i]);
else printf("%d ", ans[i]);
}
}
}
C
贪心,单个字符直接k个k个放置;两种或多个字符,若最小种字符个数 ≤ k \leq k ≤k,输出第k大的字符;两种字符再特判一下,最小种字符正好k个,次小种按k个k个放置的情况;其余情况,放置好前k个后直接全部排在一个字符后
char s[maxn];
map<int, int> mp;
vector< pair<int, int> >mpp;
int main()
{
int t; scanf("%d", &t);
while (t--) {
int n, k; scanf("%d%d", &n, &k);
scanf("%s", s); mp.clear(); mpp.clear();
for (int i = 0; i < n; ++i) {
mp[s[i] - 'a']++;
}
for (auto m : mp) {
mpp.push_back(m);
}
if (mpp.size() == 1) {
char ch = mpp[0].first + 'a';
int cnt = mpp[0].second;
int mul = cnt / k;
if (cnt % k == 0) {
for (int i = 0; i < mul; ++i) putchar(ch);
}
else for (int i = 0; i <= mul; ++i) putchar(ch);
putchar('\n');
}
else {
if (mpp[0].second < k) {
k -= mpp[0].second;
for (int i = 1; i < mpp.size(); ++i) {
if (mpp[i].second >= k) {
putchar(mpp[i].first + 'a');
putchar('\n');
break;
}
k -= mpp[i].second;
}
}
else if (mpp[0].second > k) {
putchar(mpp[0].first + 'a');
for (int i = 0; i < mpp[0].second - k; ++i) putchar(mpp[0].first + 'a');
for (int i = 1; i < mpp.size(); ++i) {
for (int j = 0; j < mpp[i].second; ++j)
putchar(mpp[i].first + 'a');
}
putchar('\n');
}
else {
if (mpp.size() == 2) {
putchar(mpp[0].first + 'a');
char ch = mpp[1].first + 'a';
int cnt = mpp[1].second;
int mul = cnt / k;
if (cnt % k == 0) for (int i = 0; i < mul; ++i) putchar(ch);
else for (int i = 0; i <= mul; ++i) putchar(ch);
putchar('\n');
}
else {
putchar(mpp[0].first + 'a');
for (int i = 1; i < mpp.size(); ++i) {
for (int j = 0; j < mpp[i].second; ++j)
putchar(mpp[i].first + 'a');
}
putchar('\n');
}
}
}
}
}
D
分析题意,根据分裂关系可得下个时间数量为 [该时间数量,该时间数量x2]之间;并且总数量是前缀和关系,因此我们需要计算的就是 a 0 + a 1 + ⋯ + a k = n a_0+a_1+\dots+a_k=n a0+a1+⋯+ak=n,其中k最小, a i − 1 ≤ a i ≤ 2 × a i − 1 a_{i-1}\leq a_i\leq 2\times a_{i-1} ai−1≤ai≤2×ai−1
直接按 2 i 2^i 2i构造序列,使前缀和 ∑ a i ≤ n \sum a_i\leq n ∑ai≤n,若sum不足补上n-sum在排序
答案即是 构造序列的差分序列
int t; scanf("%d", &t);
while (t--) {
int n; scanf("%d", &n);
int sum = 0; a.clear();
for (int i = 0; ; ++i) {
if (1ll * sum + (1 << i) > n) break;
sum += 1 << i;
a.push_back(1 << i);
}
if (n != sum) a.push_back(n - sum);
sort(a.begin(), a.end());
printf("%d\n", a.size() - 1);
for (int i = 1; i < a.size(); ++i) {
printf("%d ", a[i] - a[i - 1]);
}
printf("\n");
}
E
看了很久还是不是很会,哭了