A
给出x,y两个数,花费a元可以同时加1或减1,花费b元可以单个数加1或减1
贪心:将两个数变到同样大小,再一起减到0更优,注意特判2a和b的关系
int main()
{
int t; scanf("%d", &t);
while (t--) {
ll x, y, a, b; scanf("%lld%lld%lld%lld", &x, &y, &a, &b);
if (x < y) swap(x, y);
if (b > 2 * a) b = 2 * a;
printf("%lld\n", a * x + (b - a) * y);
}
}
B
给出t串,求t为s的子序列的满足最小循环节的s串
可以得出,可以构造的s串的最小循环节只有1或者2,特判t串的循环节是否为1
const int maxn = 1e2 + 5;
char s[maxn << 1], t[maxn];
int main()
{
int T; scanf("%d", &T);
while (T--) {
scanf("%s", &t);
int n = strlen(t);
int cnt0 = 0, cnt1 = 0;
for (int i = 0; i < n; ++i) {
if (t[i] == '0') cnt0++;
else cnt1++;
}
if (cnt0 == 0 || cnt1 == 0) {
puts(t);
continue;
}
int flg = 0;
for (int i = 0; i < n; ++i) {
if (t[i] == '0') {
if (flg == 0) flg = 1;
else if (flg == 1) {
printf("01");
}
}
else if (t[i] == '1') {
if (flg == 0) {
printf("01");
}
else if (flg == 1) {
printf("01");
flg = 0;
}
}
}
if (flg != 0) printf("01");
printf("\n");
}
}
C
给出a和b,求给出区间 x ∈ [ l , r ] x\in [l,r] x∈[l,r]之间满足 ( x m o d a ) m o d b ≠ ( x m o d b ) m o d a (x\bmod a)\bmod b\neq (x\bmod b)\bmod a (xmoda)modb=(xmodb)moda
可以知道可以求出0~r之间满足的数 与 0~l-1之间的数做差得出答案
推了很久,最后打表给出0~max(a,b)-1的数不满足,max(a,b)~LCM(a,b)的数满足。
看了别人的推导,满足的数为
x
=
k
×
l
c
m
+
x
m
o
d
a
m
o
d
b
x=k\times lcm+x\bmod a\bmod b
x=k×lcm+xmodamodb,即暴力求出0~lcm之间的情况即可
ll a, b;
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int main()
{
int t; scanf("%d", &t);
while (t--) {
int q; scanf("%lld%lld%d", &a, &b, &q);
if (a > b) swap(a, b);
int gap = a * b / gcd(a, b), incre = gap - b;
while (q--) {
ll l, r; scanf("%lld%lld", &l, &r); r++;
ll rsum = r / gap * incre + (r % gap > b ? r % gap - b : 0);
ll lsum = l / gap * incre + (l % gap > b ? l % gap - b : 0);
printf("%lld ", rsum - lsum);
}
printf("\n");
}
}
D
给出n个物品,每个物品大小为 a i a_i ai,大小范围为k,给出每个背包的现在 c i c_i ci表示大小超过i的数必须 ≤ c i \leq c_i ≤ci
因为给出 c i c_i ci满足单调递减,可以从大到小 k → 1 k\rightarrow1 k→1贪心选元素,每个背包能放就放
const int maxn = 2e5 + 5;
int cnt[maxn], c[maxn];
vector< vector<int> > res(1);
int main()
{
int n, k; scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) {
int x; scanf("%d", &x);
cnt[x]++;
}
for (int i = 1; i <= k; ++i) scanf("%d", &c[i]);
int pre = 0, ans = 0;
for (int i = k; i; --i) {
int now = 0;
if (i != k && c[i] == c[i + 1]) now = pre;
while (cnt[i]) {
if (now == ans) {
++ans;
res.emplace_back();
continue;
}
if (res[now].size() < c[i]) {
res[now].emplace_back(i);
--cnt[i];
}
else ++now;
}
pre = now;
}
printf("%d\n", ans);
for (int i = 0; i < ans; ++i) {
printf("%d", res[i].size());
for (auto j : res[i]) printf(" %d", j);
printf("\n");
}
}
E
将“车”放在nxn的棋盘上,使每个格子都要被覆盖(车可以覆盖一排和一列的格子),且互相攻击的车为k个
要覆盖所有格子,就每行或每列都存在车,画图可知,题意即求将n个元素放在n-k个集合中方案数。行列情况对称,则答案为
2
(
n
n
−
k
)
{
n
n
−
k
}
2{n\choose n-k}\left\{\begin{matrix}n\\n-k\end{matrix}\right\}
2(n−kn){nn−k}
代入第二类斯特灵公式求解
onst int maxn = 2e5 + 5;
const ll mod = 998244353;
ll fib[maxn];
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = 1ll * res * a % mod;
b >>= 1;
a = 1ll * a * a % mod;
}
return res;
}
ll c(int n, int m) {
return 1ll * fib[n] * qpow(1ll * fib[m] * fib[n - m] % mod, mod - 2) % mod;
}
int main()
{
fib[0] = 1;
for (int i = 1; i < maxn; ++i) fib[i] = 1ll * fib[i - 1] * i % mod;
ll n, k; scanf("%lld%lld", &n, &k);
if (k == 0) printf("%lld\n", fib[n]);
else if (k >= n) printf("0\n");
else {
int K = n - k;
ll ans = 0;
for (int i = 0; i <= K; ++i) {
ans = (1ll * qpow(mod - 1, i) * c(K, i) % mod * qpow(K - i, n) % mod + ans) % mod;
}
ans = 2ll * c(n, K) * ans % mod;
printf("%lld\n", ans);
}
}