Codeforces Round #697 (Div. 3)
题目链接:https://codeforces.com/contest/1475
A题:问你一个数字n是否有奇数的约数,并且这个数比1大
- 直接除以2,如果除到最后不是1的话,就是YES,否则为NO
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
int t;
cin >> t;
while(t --)
{
LL x;
cin >> x;
while(1){
if(x % 2 == 0){
x = x / 2;
}else{
break;
}
}
if(x == 1){
cout << "NO" << endl;
}else{
cout << "YES" << endl;
}
}
return 0;
}
B题:问你一个数能否由 若干个 2020 + 若干个 2021
- 可以打表,我是直接算的,差点被人hack掉,建议打表,把所有能被2020 和2021组成的数算出来
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
int t;
cin >> t;
while(t --)
{
int n;
cin >> n;
int x = 2021,y = 2020;
bool tf = false;
for(int i = 0;i < 1000;i ++)
{
for(int j = 0;j < 1000;j ++)
{
LL sum = x * i + y * j;
if(sum == n){
tf = true;
break;
}
else if(sum > n){
break;
}
}
if(tf){
break;
}
}
if(tf){
cout << "YES" << endl;
}else{
cout << "NO" << endl;
}
}
return 0;
}
C题:应该问的是你最多能找出多少对舞伴,只能是 (a,b) && (c,d) 这里 a != c && b != d
- 对于每一个人,直接找除了他本身以外的人和它的舞伴以外的人有多少个人,然后用总对数减去就Ok了,然后再加上他本身这一对
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
typedef pair<int,int> PII;
PII p[N];
int boy[N];
int gril[N];
int main()
{
int t;
cin >> t;
int a,b,k;
while(t --)
{
cin >> a >> b >> k;
for(int i = 0;i <= a;i ++) boy[i] = 0;
for(int i = 0;i <= b;i ++) gril[i] = 0;
for(int i = 0;i < k;i ++)
{
cin >> p[i].first;
boy[p[i].first] ++;
}
for(int i = 0;i < k;i ++)
{
cin >> p[i].second;
gril[p[i].second] ++;
}
LL ans = 0;
for(int i = 0;i < k;i ++)
{
ans = ans + k - (boy[p[i].first] + gril[p[i].second] - 1);
// cout << ans << endl;
}
cout << ans / 2 << endl;
}
return 0;
}
D题:想让你清理至少m的内存,a数组是你可以清理文件的内存的大小,b数组是你清理当前文件需要花费的体力
- 你需要花费少的体力在清理掉至少m内存,这里的b数组里面的数比较特殊,不是1就是2,如果是别的数字的话,可以用背包来做
- 这里我直接找的官方题解
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL t,n,m;
const int N = 1e6 + 10;
int a[N];
int b[N];
int main()
{
cin >> t;
while(t --)
{
cin >> n >> m;
LL sum = 0;
for(int i = 0;i < n;i ++){
cin >> a[i];
sum += a[i];
}
vector<int>v1;
vector<int>v2;
for(int i = 0;i < n;i ++)
{
cin >> b[i];
if(b[i] == 1){
v1.push_back(a[i]);
}else{
v2.push_back(a[i]);
}
}
if(sum < m)
{
cout << -1 << endl;
continue;
}
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
reverse(v1.begin(),v1.end());
sum = 0;
int ans = 1e9;
int j = 0;
for(int i = 0;i < v2.size();i ++){
sum += v2[i];
}
for(int i = 0;i <= v2.size();i ++){
while(j < v1.size() && sum < m){
sum += v1[j];
j ++;
}
if(sum >= m){
ans = min(ans,(int)(v2.size() - i) * 2 + j);
}
if(i == v2.size()) continue;
sum -= v2[i];
}
cout << ans << endl;
}
return 0;
}
E题:组合数模板
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int,int> PII;
PII p[N];
int a[N];
LL qmi(LL a,LL b)
{
LL res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b = b >> 1;
}
return res;
}
LL fact[N],infact[N];
//fact[i]表示i! % mod 的值
//infact[i]表示i! % mod的逆元,用乘逆元来表示除法
//组合数为:fact[a] * infact[a-b] % mod * infact[b] % mod
LL C(LL a,LL b)
{
return fact[a] * infact[a-b] % mod * infact[b] % mod;
}
int main()
{
fact[0] = 1;
infact[0] = 1;
for(int i = 1; i < N; i++){
fact[i] = fact[i-1] * i % mod;
infact[i] = qmi(fact[i], mod - 2) % mod;
}
int t;
cin >> t;
int n,k;
while(t --)
{
cin >> n >> k;
vector<int>v;
int x;
for(int i = 0;i <= n;i ++){
a[i] = 0;
}
for(int i = 0;i < n;i ++)
{
cin >> x;
v.push_back(x);
a[x] ++;
}
sort(v.begin(),v.end());
reverse(v.begin(),v.end());
int bk = k;
for(int i = 0;i < n;i ++)
{
x = v[i];
k --;
if(k == 0) break;
}
k = bk;
for(int i = 0;i < n;i ++)
{
if(v[i] == x){
break;
}
k --;
}
// cout << k << endl;
cout << C(a[x],k) << endl;
}
return 0;
}
F题:你可以修改一行,让0变成1,让1变成0,或者是修改一列,让0变成1,让1变成0
- 题解中这样说道:对于某一行,至多会被修改一次,某一列也是如此,并且修改的顺序不会影响最终结果,所以我们先判断行,如果第一个数字不同就修改这一行,然后列也进行一样的操作
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int t,n,m;
const int N = 1100;
char a[N][N];
char b[N][N];
int main()
{
cin >> t;
while(t --)
{
cin >> n;
for(int i = 0;i < n;i ++){
cin >> a[i];
}
for(int j = 0;j < n;j ++){
cin >> b[j];
}
for(int i = 0;i < n;i ++){
if(a[0][i] != b[0][i]){
for(int k = 0;k < n;k ++){
a[k][i] = a[k][i] ^ 1;
}
}
}
for(int i = 0;i < n;i ++){
if(a[i][0] != b[i][0]){
for(int k = 0;k < n;k ++){
a[i][k] = a[i][k] ^ 1;
}
}
}
bool flag = true;
for(int i = 0;i < n;i ++){
for(int j = 0;j < n;j ++){
if(a[i][j] != b[i][j]){
flag = false;
}
}
}
if(flag){
cout << "YES" << endl;
}else{
cout << "NO" << endl;
}
}
return 0;
}
/*
001
001
001
*/
G题:有点像这个题:https://ac.nowcoder.com/acm/contest/7501/A,不能说一模一样吧,但至少一模两样
- 这个题求逆,那个题求正
- 就是考察对筛法,首先大家肯定都知道排序,另外大家也都会去重,接下来就是状态方程的转移了
- dp[i] 代表的以i为结尾的最长倍数子序列的长度是多少
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int t,n,m;
const int N = 2e6 + 10;
vector<int> a;
int dp[N];
int st[N];
int main()
{
cin >> t;
while(t --)
{
cin >> n;
a.clear();
memset(dp,0,sizeof dp);
memset(st,0,sizeof st);
for(int i = 1;i <= n;i ++){
int x;
cin >> x;
a.push_back(x);
st[x] ++;
}
sort(a.begin(), a.end()); // 将所有值排序
a.erase(unique(a.begin(), a.end()), a.end());
for(int i = 0;i < a.size();i ++){
dp[a[i]] = dp[a[i]] + st[a[i]];
for(int j = 2;j <= N + 10;j ++){
if(j * a[i] >= N) break;
if(st[j * a[i]])
dp[j * a[i]] = max(dp[a[i]] ,dp[j * a[i]]);
}
}
int res = 0;
for(int i = 0;i < a.size();i ++){
res = max(dp[a[i]],res);
}
cout << n - res << endl;
}
return 0;
}
/*
3 7 9 14 63
*/
知足常乐!