Subject link: https://codeforces.com/contest/1475
Shock! At 23 o'clock in the evening on January 25, 2021, more than 30,000 people gathered on codeforces collectively! Cause the server to freeze, and finally the whole game will not be scored (⊙﹏⊙)
A. Odd Divisor
Topic
T groups of data, each group gives you an integer n, asks you if n has an odd factor other than 1, and outputs YES, otherwise it outputs NO
Range: (1≤t≤1e4, 2≤n≤10^14)
Ideas
Bit operation. Because he does not look at even factors, he can always divide by 2, and then see if the final n is 1, if it is 1, then it means all factors are even factors, otherwise there are odd factors
You can also directly look at the number of 1s in binary;
You can also directly perform lowbit operations, take the position of the rightmost 1 and start with the number represented by the last binary, and then directly compare the size with the original itself, to know whether the position of this 1 is the front, if it is the front, then it is equal to itself , That is to say, he has no odd factors, and vice versa.
ac code
Violent except 2 version
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int t; scanf("%d", &t);
while(t --){
ll n; scanf("%lld", &n);
while(n % 2 == 0) n >>= 1;
if(n == 1) puts("NO");
else puts("YES");
}
return 0;
}
lowbit version
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) x & (-x)
int main(){
int t; scanf("%d", &t);
while(t --){
ll n; scanf("%lld",&n);
ll d = lowbit(n);
if(d == n) puts("NO");
else puts("YES");
}
return 0;
}
B. New Year's Number
Topic
T groups of data, each group is given an integer n, ask you if n can be the result of adding a 2020 and b 2021.
Range: (1≤t≤1e4, 1≤n≤10^6)
Ideas
n=a*2020+b*2021 can be transformed into n=2020*(a+b)+b by associative law, then a+b here becomes n/2020, and b becomes n%2020. The transformation condition of this equation is b>=a, because b is enough to merge into (a+b)*2020.
ac code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int t; scanf("%d", &t);
while(t --){
int n; scanf("%d", &n);
int a1 = n % 2020;
int a2 = n / 2020;
if(a1 <= a2) puts("YES");
else puts("NO");
}
return 0;
}
C. Ball in Berland
Topic
There are a man and b woman participating in the dance, and there are k pairs, which means that two people can dance together. Then there are four people to form two dance teams. How many ways?
In the t group of data, there are three numbers a, b, and k in the first row of each group, the k numbers in the second row represent the serial number ai of the man, and the third row bi represents the serial number of the lady, and ai and bi can dance together.
Range: (1≤t≤1e4, 1≤a,b,k≤2e5, 1≤ai≤a, 1≤bi≤b)
Ideas
Open two vector arrays and save them. v1[i] represents the numbers of the ladies who can dance with the man i, and v2[i] represents the numbers of the men who can dance with the woman i.
Then traverse v1[i], it is i’s dancing partner, then v1[i].size()+v2[it].size()-1 is all the people related to these two, then these edges can no longer be taken , Because if it is taken, it will be a bit repetitive, either point i or point it. The rest is k-(v1[i].size()+v2[it].size()-1), these relationships do not have any repetition with i and it, and can be used as the second dance team, then the traversal accumulation is However, because there is no order for the first pair and the second pair, remember to divide the final result by 2.
ac code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
vector<int> v1[maxn], v2[maxn];
int a[maxn], b[maxn];
int main(){
int t; scanf("%d", &t);
while(t --){
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i ++) v1[i].clear();
for(int i = 1; i <= m; i ++) v2[i].clear();
for(int i = 1; i <= k; i ++){
scanf("%d", &a[i]);
}
for(int i = 1; i <= k; i ++){
scanf("%d", &b[i]);
v1[a[i]].push_back(b[i]);
v2[b[i]].push_back(a[i]);
}
ll ans = 0;
for(int i = 1; i <= n; i ++){
for(auto it : v1[i]){ //遍历vector v1[i]
ans += k - (v1[i].size() + v2[it].size() - 1);
}
}
cout << ans / 2 << endl;
}
return 0;
}
D. Cleaning the Phone
Topic
Clear memory, each application has the value of ai's memory and bi.
t group of data, each group of two integers n, m, respectively representing n applications and the memory that needs to be cleaned up s, the next line is n numbers representing application memory ai, and the next line is n numbers representing application value bi, ask you where On the premise that the cleaned memory is not less than m, the value of deletion is minimized, and the minimum value is output.
Range: (1≤t≤1e4,1≤n≤2e5,1≤m≤1e9,1≤ai≤1e9,1≤bi≤2)
Ideas
First, open two arrays to store all applications whose value is 1, 2 respectively, and then sort them according to the memory size of all applications from large to small. The final selection must be a value of 1 and b value of 2. If you want to choose a, you must have the largest sum of a memory, so find a prefix sum for the sorted array, then for the prefix and suma[i] it means to take the i largest memory with a value of 1, then If s-suma[i] is left, take it from the value 2 and do the same here, find the prefix and sumb, and then find the first subscript greater than or equal to s-suma[i]. If the subscript exceeds The range indicates that it does not exist. If there is an id, you can delete the memory that is not less than s, and then the sum of its value is i + id * 2, just update the minimum value.
ac code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
const int inf = 0x3f3f3f3f;
int w[maxn], v[maxn];
int main(){
int t; cin >> t;
while(t --){
vector<ll> v1, v2; //v1存价值为1的应用的内存,v2存价值为2的应用的内存
int n, s;
ll sum = 0;
cin >> n >> s;
for(int i = 1; i <= n; i ++){
cin >> w[i];
sum += w[i];
}
for(int i = 1; i <= n; i ++){
cin >> v[i];
if(v[i] == 1) v1.push_back(w[i]);
else v2.push_back(w[i]);
}
if(sum < s){ //如果所有应用内存加起来都低于s,那直接出-1
puts("-1");
continue;
}
sort(v1.begin(), v1.end(), greater<int>()); //按从大到小排
sort(v2.begin(), v2.end(), greater<int>());
v1.insert(v1.begin(), 0); //选0个应用的时候,内存是0
v2.insert(v2.begin(), 0);
for(int i = 1; i < v1.size(); i ++) v1[i] += v1[i - 1]; //求前缀
for(int i = 1; i < v2.size(); i ++) v2[i] += v2[i - 1];
int ans = inf;
for(int i = 0; i < v1.size(); i ++){
int id = lower_bound(v2.begin(), v2.end(), s - v1[i]) - v2.begin(); //找剩余内存的位置
if(id < v2.size()) ans = min(ans, i + id * 2); //更新最小值
}
cout << ans << endl;
}
return 0;
}
E. Advertising Agency
Topic
T group of data, each group of data gives you two numbers n, k, then n numbers ai, and then asks you to take k numbers to get the maximum value. There are several ways to choose (mod 1e9+7)
Range (1≤t≤1000, 1≤k≤n≤1000)
Ideas
Number of combinations. The maximum value must be obtained from large to small, and the number is maintained by map. If ai is obtained, there are d ai, and m is easy to take, then there are C(d,m) methods.
The range of n is not large, and the combination number array c can be initialized according to Yang Hui's triangle. c[i][j]=c[i-1][j]+c[i-1][j-1].
ac code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
int c[1005][1005];
void init(){
c[0][0] = 1;
for(int i = 1; i <= 1000; 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;
}
}
int main(){
init();
int t; scanf("%d", &t);
while(t --){
map<int, int, greater<int> >mp; //按照第一键值从大到小排
int n, m;
scanf("%d%d", &n, &m);
while(n --){
int x; scanf("%d", &x);
mp[x] ++;
}
for(auto it : mp){ //从大到小取
int d = it.second;
if(d >= m) { // m不够,才有取法
printf("%d\n", c[d][m]);
break;
}
m -= d; // m足够,那么取完d
}
}
return 0;
}
F. Unusual Matrix
Topic
There are t groups of data, each group of data has an n, and then two n*n matrices A and B, the value is 0 or 1. There are two operations, which are to select a row to flip (0 to 1, 1 to 0), and to select a column to flip. Ask if you can turn matrix A into matrix B through these two operations.
Range: (1≤t≤1000, 1≤n≤1000)
Ideas
Structure questions. Two kinds of reversal, the order will not affect the result. First, define a two-dimensional matrix C to indicate whether A[i][j] and B[i][j] are the same. If they are not the same, it is 1, and when they are the same, the problem is converted into a zero matrix. Then see if the first digit of each row is 1, if it is 1, then perform the row transformation. In this case, the row transformation ends, and then see if each row is the same. If they are all the same, then it can be eliminated by column transformation. All are different.
ac code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1005;
string a[maxn], b[maxn], c[maxn];
int main(){
int t; cin >> t;
while(t --){
int n; cin >> n;
for(int i = 0; i < n; i ++) cin >> a[i];
for(int i = 0; i < n; i ++) cin >> b[i];
for(int i = 0; i < n; i ++) {
for(int j = 0; j < n; j ++) {
if(a[i][j] == b[i][j]) c[i] += "0";
else c[i] += "1";
}
if(c[i][0] == '1'){
for(int j = 0; j < n; j ++){ //行变换,1-1=0,1-0=1 实现翻转
c[i][j] = '1' - (c[i][j] - '0');
}
}
}
int flag = 1;
for(int i = 0; i < n; i ++){
if(c[i] != c[0]){ //判断每行是否相同
flag = 0;
break;
}
}
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
G. Strange Beauty
Topic
Perfect sequence: Take any two values a and b in the sequence, and there are either a divisible by b or b divisible by a.
Then give you a sequence of length n, and ask you to delete at least a few numbers to make the remaining sequence a perfect sequence.
Range: (1≤t≤10, 1≤n≤2e5, 1≤ai≤2e5)
Ideas
dp. The meaning of the question can be transformed into finding the longest perfect sequence, which is similar to an sieve in the recursive form.
Assume that the perfect sequence here is in ascending order. dp[i] represents the maximum length of a perfect sequence with i at the end, and then cnt[i] represents the number of i, and then the next value j should be a multiple of i, because it is only related to i, then double the traversal .
Recursively, update the value, and then if i can be the end, j can also be the end, so dp[j] can be equal to dp[i], and then dp[j] takes the largest dp[i], That is, dp[j]=max(dp[i])(j%i==0). Finally, update the maximum value of dp[i].
The final answer is n-maximum, because what you want is the deleted number.
ac code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
int dp[maxn], cnt[maxn];
int main(){
int t; scanf("%d", &t);
while(t --){
int n, mx = -1; scanf("%d", &n);
for(int i = 1; i <= n; i ++){
int x; scanf("%d", &x);
cnt[x] ++;
mx = max(mx, x);
}
int ans = 0;
for(int i = 1; i <= mx; i ++){
dp[i] += cnt[i]; //加上i的个数,因为后面递推的时候没有算上他的个数
for(int j = i * 2; j <= mx; j += i){
dp[j] = max(dp[j], dp[i]);
}
ans = max(ans, dp[i]);
}
printf("%d\n", n - ans);
for(int i = 1; i <= mx; i ++){
cnt[i] = dp[i] = 0;
}
}
return 0;
}