从博客园转攻CSDN
第一篇就总结下九月里做过的题吧
战况预览
9.19
C. Array Elimination
https://codeforces.com/problemset/problem/1602/C
类型:二进制 难度:1300
二进制不熟悉的小伙伴可以多做些之类的题, 自然就会了~
题意
n个数,要求找出所有的k,使得操作后所有数都为0
操作: 每次选择k个数,计算x=ai1 & ai2 & … & aik 然后其中(ai1、ai2 … aik)每个数都减去x
题解
补充: 只有1&1=1, 其它结果都是0
取几个数哪一位二进制都是1, 然后他们一起&, 就能消除二进制的这个1
为了保证每个二进制的1都能消除, 所以k应该取每一位1的数目的公因数。也就是找出最大公因数(gcd), 输出gcd的所有因数
例: 13和7
13 - 1101
7 - 111
13和7&的结果就是 5(101),
13和7减去5就消去了倒数第一位和倒数第三位的1
代码
#include <bits/stdc++.h>
#include <stack>
#include <queue>
typedef long long LL;
using namespace std;
const int N = 2e5+10;
int a[N], res[40];
void f(int x)
{
for(int i = 32; i >=0; i --)//i=20也没有问题,因为n<2e5
{
res[i] += ((x>>i)&1);
}
}
int main()
{
int t;
cin >> t;
while(t --)
{
memset(res, 0, sizeof res);
int n;
cin >> n;
for(int i = 0; i < n; i ++)
{
cin >> a[i];
f(a[i]);
}
int ans = 0;
for(int i = 0; i <= 32; i ++)
{
if(ans == 0 && res[i]!=0) ans = res[i];
else if(res[i]!=0) ans = __gcd(ans, res[i]);//ans是最大公约数
}
for(int i = 1; i <= n && i<=ans; i ++)//输出ans的所有因数
if(ans%i==0)
cout << i << ' ';
cout <<endl;
}
return 0;
}
9.18
B. And It’s Non-Zero
https://codeforces.com/problemset/problem/1615/B
类型: 二进制,前缀和 难度:1300
题意
给出l, r ,要求删去区间[l, r] 里最少的数使得所有数&后不等于0
题解
此题不难想到找出二进制哪一位1的个数最大, 并用n减去这个数就行了
难点在于暴力求解 1e4*2e5会超时, lowbit优化也不可以。想办法去优化多次计算的部分,可以考虑前缀和,因为数都是1~2e5里连着数
代码
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 2e5+10;
map<int,int> mp[N];
void init()
{
for(int j = 0; j < 21; j ++) mp[0][j]=0;
for(int i = 1; i < N ; i ++)
for(int j = 0; j < 21; j ++)
mp[i][j] = (i>>j&1)+mp[i-1][j];
}
int main()
{
init();
int t;
cin >> t;
int n = 0;
int l, r;
while(t --)
{
int res=0;
cin >> l >> r;
for(int i = 0; i < 21; i ++)
res = max(res, mp[r][i]-mp[l-1][i]);
cout<<r-l+1-res<<'\n';
}
return 0;
}
C. LIS or Reverse LIS?
https://codeforces.com/problemset/problem/1682/C
类型:数字构造,排序 难度:1400 不难
题意
lis()表示序列严格单增的数字个数,不含相等
要求根据已知n个数排列后构造出min(lis(a1,a2,an), lis(an,a2,a1) )的最大值
题解
要求就是构造出山峰,求山顶到两边最近山底的最大值,把序列排序后,从前往后遍历,出现过小于等于两次的数(山顶左边放一个,山顶右边放一个)都可以计入来构造山,最后偶数 = 总数/2 奇数 =(总数+1)/ 2
代码
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 2e5+10;
int a[N];
int main()
{
int m;
cin >> m;
while(m --){
int n, s=0;
cin >> n;
for(int i = 0; i < n; i ++) cin >> a[i];
sort(a, a+n);//感觉不排序也可~
map<int,int> st;
for(int i = 0; i < n; i ++)
{
if(st[a[i]]<=1) s++;
st[a[i]]++;
}
cout<<(s+1)/2<<'\n';
}
return 0;
}
9.14
C. Mocha and Hiking
https://codeforces.com/problemset/problem/1559/C
类型: 构造图 难度:1200 此题不难
题意
有n+1个点, 2n-1条路, 其中有n-1条路是从i到i+1
另外n条路根据输入, 在序列 a1, a2… an 中, ai =0是从 i 到n+1有一条路, =1是从n+1到 i 有一条路
要求连接1到n+1个点, 且每个点只用一次
题解
1~n都是连接的, 所以此题的关键是如何将n+1插入进来, 共有3种方式
1.插入末尾
2.插入开头
3.插入中间, 满足ai-1=0, ai=1即可
代码
#include <iostream>
typedef long long LL;
using namespace std;
const int N = 1e5+10;
bool a[N];
// If ai=1, n+1 to village i.
int main()
{
int m;
cin >> m;
while(m --){
int n;
cin >> n;
for(int i = 0; i < n; i ++) cin >> a[i];
if(a[n-1] == 0)
{
for(int i = 1; i <= n+1; i ++) cout << i << ' ';
}
else if(a[0]==1)
{
cout << n+1<< ' ';
for(int i = 1; i <= n; i ++) cout << i << ' ';
}
else
{
int f = 0;
for(int i = 1; i < n; i ++)
{
if(a[i]==1 && a[i-1]==0 ) f=i;
}
if(f)
{
for(int i = 1; i <= f; i ++) cout << i << ' ';
cout << n+1 << ' ';
for(int i = f+1; i <= n; i ++) cout << i << ' ';
}
else puts("-1");
}
cout << '\n';
}
return 0;
}