A题
题目大意
判断一个整数 n ,是否存在大于 1 的奇数因子
思路
判断 n 是不是 2 的整数幂即可
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;
int main() {
int ncase;
cin >> ncase;
while(ncase--){
ll n;
cin >> n;
while(n % 2 == 0) n /= 2;
if(n != 1) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
B题
题目大意
判断 n 是否存在一对 (x,y)使得 2020 * x + 2021 * y = n
思路
令 a = n / 2020, b = n % 2020, 如果 b 小于等于 a,我们也就可以在 a 个2020,分出 b 个 2020 和剩下的 b 凑成 b 个2021。
如果 b <= a, 就是 yes,否则就是 no
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;
int main() {
int ncase;
cin >> ncase;
while(ncase--){
ll n;
cin >> n;
int a = n / 2020;
int b = n % 2020;
if(a < b) cout << "NO" << endl;
else cout << "YES" << endl;
}
return 0;
}
C题
题目大意
给出 k 对数 (ai, bi),询问有多少对( ai bi ) , ( aj , bj ) 使得ai ! = aj , bi ! = bj
思路
容斥原理
对于 (ai, bi) 满足的 ( aj , bj ) 的个数有:k - num(ai) - num(bi) + num(ai,bi)
统计所有的对数,再除二就OK
注意别爆int
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;
int a[maxn];
int b[maxn];
int aa[maxn];
int bb[maxn];
map<pair<int, int>, int> v;
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
int main() {
int ncase;
read(ncase);
while(ncase--){
ll n, m, k;
read(n); read(m);read(k);
for(int i = 1; i <= k; i++) read(a[i]);
for(int j = 1; j <= k; j++) read(b[j]);
for(int j = 1; j <= n; j++) aa[j] = 0;
for(int j = 1; j <= m; j++) bb[j] = 0;
for(int j = 1; j <= k; j++) aa[a[j]]++;
for(int j = 1; j <= k; j++) bb[b[j]]++;
for(int j = 1; j <= k; j++) v[{a[j], b[j]}]++;
ll res = 0;
for(int i = 1; i <= k; i++){
res += 1ll * k - 1ll * aa[a[i]] - 1ll * bb[b[i]] + 1ll * v[{a[i], b[i]}];
}
printf("%lld\n", res / 2);
v.clear();
}
return 0;
}
D题
题目大意
给出N个物品,每个物品有一个质量和花费,求出在质量大于等于m时的最小花费。
思路
做法 题目数据范围说了花费只会是1或者2,所以我们开两个数组,存1和2的花费
因为在花费相同的情况下,肯定优先选大的质量,所以我们从大到小排序,然后我们去枚举花费1用了多少个,然后二分找出花费2需要多少个,用前缀和优化即可
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const int INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
const int N=1005;
using namespace std;
ll c[maxn];
ll a[maxn] = {0}; // 存 1
ll b[maxn] = {0}; // 存 2
bool cmp(ll x, ll y){
return x > y;
}
int main() {
int ncase;
cin >> ncase;
while(ncase--){
ll n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> c[i];
ll sum = 0, f, cnt1 = 0, cnt2 = 0;
for(int i = 1; i <= n; i++){
cin >> f;
if(f == 1) a[++cnt1] = c[i];
else b[++cnt2] = c[i];
sum += c[i];
}
if(sum < m){
cout << -1 << endl;
continue;
}
sort(a+1, a+1+cnt1, cmp);
sort(b+1, b+1+cnt2, cmp);
a[0] = b[0] = a[cnt1+1] = b[cnt2+1] = 0;
for(int i = 1; i <= cnt1; i++) a[i] += a[i-1];
for(int i = 1; i <= cnt2; i++) b[i] += b[i-1];
int res = INF;
for(int i = 0; i <= cnt1; i++){
ll tmp = m - a[i];
int ind = lower_bound(b + 1, b + 1 + cnt2, tmp) - b;
if(a[i] + b[ind] >= m) res = min(res, i + ind * 2);
ind--;
if(a[i] + b[ind] >= m) res = min(res, i + ind * 2);
}
if(res == INF) res = -1;
cout << res << endl;
}
return 0;
}
E题
题目大意
给出 n 个数,长度为 m 的子序列且子序列的sum最大,问这样的子序列有多少个。
思路
组合数
先排序,根据贪心思想,我们一定会选前 m 大的数。
我们设前 m 大的数里有 x 个不同的数构成(eg:1、2、3、3,前 3 大的数由2 和 3 构成,x = 2)。
可以确定,排序后的x个不同的数,在前 x-1 个数一定会全部被选(设有 z 个),在第 x 大的数中选 m - z 个数。
设v[ai] 为 a[i] 的个数,也就是说算一下组合数C(m-z,v[ai] )。
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
map<int, ll> v;
ll a[1005];
ll V[2005][2005] = {0};
void init(){
V[0][0] = V[1][1] = V[1][0] = 1;
for(int i = 2; i <= 2000; i++){
V[i][0] = 1;
for(int j = 1; j <= i; j++){
V[i][j] = (V[i-1][j-1] + V[i-1][j]) % mod;
}
}
}
int main() {
init(); // 预处理组合数
int ncase;
read(ncase);
while(ncase--){
ll n, m;
read(n); read(m);
for(int i= 1; i <= n; i++) read(a[i]);
for(int i= 1; i <= n; i++) v[a[i]]++;
sort(a+1, a+1+n);
a[n+1] = 0;
ll res = 1;
for(int i = n; m; i--){
if(a[i] == a[i+1]) continue;
if(m >= v[a[i]]) m -= v[a[i]];
else res = V[v[a[i]]][m], m = 0;
}
cout << res << endl;
v.clear();
}
return 0;
}
F题
题目大意
给出两个 01 矩阵,A 与 B。每次可以对 A 的一行的所有数和 1 进行异或,或者对 A 的一列的所有数和 1 进行异或,询问是否可以通过一系列的操作使得 A 变成 B 。
思路
考虑奇偶性:
如果对一行进行奇数次操作,这一行会发生变化。
如果对一行进行偶数次操作,这一行不会发生变化。(原因: x ^ x = 0,0 ^ x = x)
首先遍历最左一列的数字,若A与B中的不同,则对一整行元素进行异或运算,遍历完之后应该不会有更多行异或的操作,因此,从第二列开始遍历,此时矩阵A与矩阵B在同一列中的元素应该全部相等或者全部相反,若出现矛盾,则矩阵A不能通过变换到达矩阵B。
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
const int N=1005;
using namespace std;
int v[1005][1005] = {0};
int lin[1005] = {0};
int row[1005] = {0};
int main() {
int ncase;
cin >> ncase;
while(ncase--){
int n;
cin >> n;
char a[1005];
for(int i = 1; i <= n; i++){
cin >> (a+1);
for(int j = 1; j <= n; j++){
if(a[j] == '1') v[i][j] ^= 1;
else v[i][j] ^= 0;
}
}
for(int i = 1; i <= n; i++){
cin >> (a+1);
for(int j = 1; j <= n; j++){
if(a[j] == '1') v[i][j] ^= 1;
else v[i][j] ^= 0;
}
}
for(int i = 1; i <= n; i++){
if(v[i][1]){
for(int j = 1; j <= n; j++){
v[i][j] ^= 1;
}
}
}
int f = 1;
for(int i = 2; i <= n; i++){
for(int j = 2; j <= n; j++){
if(v[1][i] != v[j][i]){
f = 0;
break;
}
}
if(f == 0) break;
}
if(f) cout << "YES" << endl;
else cout << "NO" << endl;
chushi(v, 0); chushi(lin, 0); chushi(row, 0);
}
return 0;
}
G题
题目大意
定义一个数组是好的,当前仅当任意两个数 ai 和 aj 都满足 ai % aj = 0 或者 aj % ai = 0 ,问最少删除几个数使得数组变好。
思路
DP
dp[i] 表示以 i 作为最小因子组成的好数组的元素个数。
则:dp[i * j] = max(dp[i * j], dp[i] + v[i*j]); ( j 为 2 到 x, i * x > amax )
AC代码
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
const int N=1005;
using namespace std;
int v[maxn] = {0};
int dp[maxn] = {0};
int main() {
int ncase;
cin >> ncase;
while(ncase--){
int n;
cin >> n;
int num, mx = -1;
for(int i = 1; i <= n; i++){
cin >> num;
v[num]++;
mx = max(mx, num);
}
for(int i = 1; i <= mx; i++) dp[i] = v[i];
for(int i = 1; i <= mx; i++){
if(v[i] == 0) continue;
for(int j = 2; j * i <= mx; j++){
if(v[i * j] == 0) continue;
dp[i * j] = max(dp[i * j], dp[i] + v[i*j]);
}
}
int res = -1;
for(int i = 1; i <= mx; i++) res = max(res, dp[i]);
cout << n - res << endl;
chushi(dp, 0); chushi(v, 0);
}
return 0;
}