(1)题目大意
给你一个a数组表示内存大小,b数组表示方便度,问你要释放m内存后,剩余的方便度最大是多少。
(2)解题思路
明显的贪心思路是,我们按从大打到小排序方便度为1和为2的内存大小,然后预处理出为1和为2的方便度的数组的前缀和,然后我们枚举取多少个1,二分出还需要多少个2,然后答案取min,但是可能没有方便度为1的,所以我们还需要枚举单独取多少个2能达到m内存,再取min即可。
(3)代码实现
// Problem: D. Cleaning the Phone
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/D
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
PII p[N];
int n, m;
void solve()
{
cin >> n >> m;
ll tot = 0, ans = INT_MAX;
for (int i = 1; i <= n; i++)
{
cin >> p[i].fi;
tot += p[i].fi;
}
vector<ll> v1, v2;
vector<ll> s1, s2;
for (int i = 1; i <= n; i++)
{
cin >> p[i].se;
if (p[i].se == 1)
{
v1.push_back(p[i].fi);
}
else
{
v2.push_back(p[i].fi);
}
}
if (tot < m)
{
cout << "-1" << endl;
return;
}
sort(v1.rbegin(), v1.rend());
sort(v2.rbegin(), v2.rend());
ll pre1 = 0, pre2 = 0;
for (int i = 0; i < v1.size(); i++)
{
pre1 += v1[i];
s1.push_back(pre1);
}
for (int i = 0; i < v2.size(); i++)
{
pre2 += v2[i];
s2.push_back(pre2);
}
for (int i = 0; i < s1.size(); i++)
{
ll val = s1[i], cnt = i + 1;
if (val >= m)
{
ans = min(ans, cnt);
continue;
}
auto it = lower_bound(s2.begin(), s2.end(), m - val);
if (it == s2.end())
{
continue;
}
else
{
ans = min(ans, cnt + ((it - s2.begin()) + 1) * 2);
}
}
for (int i = 0; i < s2.size(); i++)
{
ll val = s2[i], cnt = i + 1;
if (val >= m)
{
ans = min(ans, 2 * cnt);
}
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
solve();
return 0;
}
(1)题目大意
给你一个n,k还有一个a数组,问你在长度为n种选k个的和最大值的方案数是多少
(2)解题思路
显然我们首先排序看多少位置和n-k+1这个位置的数相等,然后我们考虑设右边有r个,总共有tot个,那么答案就是C(tot,k)
(3)代码实现
// Problem: E. Advertising Agency
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int mod = 1e9 + 7;
const int N = 5e3 + 10;
int a[N];
ll C[N][N];
void init()
{
int n = 5000;
C[0][0] = 1;
for (int i = 1; i <= n; i++)
{
C[i][0] = 1;
for (int j = 1; j <= i; j++)
{
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
}
}
void solve()
{
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a + 1, a + 1 + n);
int tot = 0, r = 0, idx = n - k;
for (int j = idx + 1; j <= n; j++)
{
if (a[j] == a[idx])
{
r++;
}
else
{
break;
}
}
tot = r + 1;
for (int j = idx - 1; j >= 1; j--)
{
if (a[j] == a[idx])
{
tot++;
}
else
{
break;
}
}
cout << C[tot][r] << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
init();
cin >> T;
while (T--)
solve();
return 0;
}
(1)题目大意
给你两个只含01的矩阵a和b,问你是否能通过两个操作(无限次数)把a数组变成b数组,第一个操作是:选一个一行翻转,第二个操作是选择一列翻转。
(2)解题思路
我们可以把一行一列看成一个整体,如果A[i][j] != B[i][j],说明行或者列只能翻一个,否则A[i][j] = B[i][j]要么就是行和列都翻,或者都不翻,(要注意建反边)因此考虑2-SAT,跑出来若不矛盾,则说明有解。
(3)代码实现
// Problem: F. Unusual Matrix
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 1e3 + 10;
struct Edge
{
int nt, to;
} e[N * N * 4 + 10];
char A[N][N], B[N][N];
int he[N * 4 + 10], idx, dfn[N * 4 + 10], low[N * 4 + 10], tim, ins[N * 4 + 10], id[N * 4 + 10], cor;
int n, stk[N * 8], top = 0;
void add(int a, int b)
{
e[idx] = {he[a], b};
he[a] = idx++;
}
void tarjan(int now)
{
dfn[now] = low[now] = ++tim;
ins[now] = true, stk[++top] = now;
for (int i = he[now]; ~i; i = e[i].nt)
{
int j = e[i].to;
if (!dfn[j])
{
tarjan(j);
low[now] = min(low[now], low[j]);
}
else if (ins[j])
{
low[now] = min(low[now], dfn[j]);
}
}
if (low[now] == dfn[now])
{
cor++;
int y;
do
{
y = stk[top--];
id[y] = cor;
ins[y] = false;
} while (y != now);
}
}
void solve()
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%s", A[i]);
}
for (int i = 0; i < n; i++)
{
scanf("%s", B[i]);
}
top = 0, tim = 0, idx = 0, cor = 0;
for (int i = 0; i <= 4 * n; i++)
{
he[i] = -1;
dfn[i] = low[i] = ins[i] = id[i] = 0;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (A[i - 1][j - 1] != B[i - 1][j - 1])
{
add(j + n * 3, i);
add(i, j + n * 3);
add(i + n, j + 2 * n);
add(j + 2 * n, i + n);
}
else
{
add(i + n, j + 3 * n);
add(j + n * 3, i + n);
add(j + n * 2, i);
add(i, j + n * 2);
}
}
}
for (int i = 1; i <= 4 * n; i++)
{
if (!dfn[i])
{
tarjan(i);
}
}
for (int i = 1; i <= n; i++)
{
if (id[i] == id[i + n])
{
puts("NO");
return;
}
}
for (int i = 2 * n + 1; i <= 3 * n; i++)
{
if (id[i] == id[i + n])
{
puts("NO");
return;
}
}
puts("YES");
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
solve();
return 0;
}
(1)题目大意
给你一个数组A,问你最少删除多少个元素后,A中的元素都有倍数关系。
(2)解题思路
考虑埃筛思路,我们枚举每个数的倍数是否出现在这个数组中,如果出现了,那么可以直接建边,在建完边后,考虑用拓扑排序+dp处理出最大能包含多少个,然后枚举一遍dp取个最大的就可以了。
(3)代码实现
// Problem: G. Strange Beauty
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/G
// Memory Limit: 256 MB
// Time Limit: 5000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
int a[N], have[N], in[N], dp[N], vis[N];
vector<int> G[N];
void solve()
{
int n;
cin >> n;
int ans = n - 1;
for (int i = 1; i <= 2e5; i++)
{
vis[i] = dp[i] = in[i] = have[i] = 0;
G[i].clear();
}
for (int i = 1; i <= n; i++)
{
cin >> a[i];
have[a[i]]++;
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
{
if (a[i] == a[i - 1])
continue;
for (int j = a[i] + a[i]; j <= 2e5; j += a[i])
{
if (have[j])
{
in[j]++;
G[a[i]].push_back(j);
}
}
}
queue<int> q;
for (int i = 1; i <= n; i++)
{
dp[a[i]] = have[a[i]];
ans = min(ans, n - dp[a[i]]);
if (in[a[i]] == 0)
{
q.push(a[i]);
}
}
while (q.size())
{
int v = q.front();
q.pop();
vis[v] = true;
for (auto x : G[v])
{
dp[x] = max(dp[x], dp[v] + have[x]);
if (!vis[x])
{
q.push(x);
}
}
}
for (int i = 1; i <= n; i++)
{
ans = min(ans, n - dp[a[i]]);
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
solve();
return 0;
}