直接模拟
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define has1 __builtin_popcount
void solve()
{
long long a, b, n;
cin >> a >> b >> n;
long long sum = b;
for (int i = 0; i < n; i++)
{
ll x;
cin >> x;
if (x >= a)
{
sum += a - 1;
}
else
{
sum += x;
}
}
cout << sum << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
博弈论问题,分操作次数k的奇偶来判断,谁是最后手,不难看出,对于双方操作是有周期性的,赛时想直接猜测最后一次操作换与不换直接求出结果,但是wa了,后面直接对奇偶都取了个特定值,暴力模拟
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define has1 __builtin_popcount
void solve()
{
ll n, m, k, t;
cin >> n >> m >> k;
unsigned long long sum1 = 0, ans;
vector<ll> a(n), b(m);
if (k % 2 == 0)
{
k = min((long long)10, k);
}
else
{
k = min((ll)9, k);
}
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
for (int i = 0; i < m; i++)
{
cin >> b[i];
}
sort(a.begin(), a.end());
sort(b.begin(), b.end());
for (int i = 0; i < k; i++)
{
if (i % 2 == 0)
{
if (a[0] < b[m - 1])
{
t = a[0];
a[0] = b[m - 1];
b[m - 1] = t;
}
}
else
{
if (b[0] < a[n - 1])
{
t = b[0];
b[0] = a[n - 1];
a[n - 1] = t;
}
}
sort(a.begin(), a.end());
sort(b.begin(), b.end());
}
for (int i = 0; i < n; i++)
{
// cout << a[i] << " ";
sum1 += a[i];
}
cout << sum1 << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
求一个s,是否有(2^s)*n%m==0,直接判断是否可分,对于可以分尽的操作,对半切的次数是有限的,直接模拟
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
ll n, m;
cin >> n >> m;
if (n % m == 0)
{
cout << 0 << "\n";
return;
}
if ((n << 32) % m) // 说明经过多次乘2还是无法分尽
{
cout << -1 << endl;
return;
}
n %= m;
ll ans = 0;
while (true)
{
ans += n;
n = (n * 2) % m;
if (n == 0)
{
cout << ans << "\n";
return;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
一:当mex=0时,删除元素后mex还是0,也就是说,要花费尽量少的代价,将mex转为0
二:当a[i]>mex时,删除此a[i],代价为mex,对于最小的总代价没有好处,不予考虑,故考虑0-mex-1的元素
三、当此时mex=i时,想要mex->j,需要删除掉所有的j,假如j的数量为k,则删除前k-1个后,代价为当时的mex=i,当删除第k个j后,mex=j,即代价为j,此时和删除一个j-1是一样的代价,把它归并到这里即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define has1 __builtin_popcount
#define N 5005
int a[N], f[N], k[N]; k[i]表示a数组中值为i的数量,f[i]表示将mex(a数组)变为i时的花费
void solve()
{
int n;
cin >> n;
memset(f, 0x7f7f, sizeof(f));
memset(k, 0, sizeof(k));
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a, a + n);
ll mex = 0; // 初始的mex
for (int i = 0; i < n; i++)
{
if (a[i] == mex) // 如果是有数可以到达mex,说明前面是连续的
{
k[mex++] = 1;
}
else if (mex > a[i]) // 这样应该是mex=a[i]+1,记录a[i]的数量
{
k[a[i]]++;
}
else
{
break; // a[i]>mex的数都是没有意义的,这样并不会让代价更小
}
}
f[mex] = 0;
for (int i = mex; i >= 0; i--) // 遍历mex
{
for (int j = 0; j < i; j++) // mex从i->j
{
f[j] = min(f[j], f[i] + i * (k[j] - (i == mex))); // 如果i==mex,前驱k[j]-1个,mex都是原来的mex,剪掉最后一个后,变为前一个数mex-1,这里的一次就并到那里去
// // 如: 值:0 1 2 3 5
// // 数量: 1 2 3 4 5
// // 初始时mex=4,当mex从4->3时,需要删除所有的4,当删除前3个4时,mex一直为4,删除最后一个4后,mex=3,这里与mex=3,删除一个2是一致的,所以并到那里去就可以了
}
}
cout << f[0] << endl; // 当mex=0时,删除元素后mex依旧是0,代价不变;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}