K.Bit位运算
题意:
0到r中,选择一个数x进行n次操作,所得最大值是多少。
- 操作1a:x=x & a
- 操作2a:x=x | a
- 操作3a:x=x ^ a q个r
思路:
- 通过与、或、异或运算性质可以知道,最后每一位能变成什么样子,取决于最后一个与运算(若没有与运算则就是所有操作累计起来的结果)及以后操作累计起来的结果,所以我们需要一个变量来记录最终全部操作进行完每一位的情况,最后我们需要在那些为0的位置上贪心地从大到小选择一些位置,使得这些位置为1组成的数进行完所有操作后值最大,然后还需要记录经过这些操作以后的最大值是多少,改变的时候只需要改变最大值该位为1而累计起来的结果为0的位置需要置为1
- 做法:二进制拆位,贪心。
- 这其实是一个非常套路的题目,由于这 n 个操作是固定的,而且
与二进制有关,所以不妨从二进制的角度去考虑。
我们可以预先处理出二进制第 i 位初始为 1 或 0 时,经过这 n
次操作之后它的变化。然后对于每一个询问,从二进制的高位到
低位枚举,判断数 x 的当前位应该为 1 还是 0,如果当前位初始
为 0 时能得到 1,则优先将当前位置为 0。若当前位初始为 1 时
能得到 1,且将当前位置为 1 后仍不超过 r 的限制,也将当前位
置为 1。这么贪心选取出的 x 一定满足它经过这 n 个操作之后
得到的数是最大的。
时间复杂度:O(30 × (n + q))
代码:
#include<bits/stdc++.h> using namespace std; int b=INT_MAX,b1=0; int n,m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { int op,x; cin>>op>>x; if(op==1)b&=x,b1&=x; else if(op==2)b|=x,b1|=x; else b^=x,b1^=x; } while(m--) { int r; cin>>r; int ans=0; for(int i=30;i>=0;i--) { if(b>>i&1&&(b1>>i&1)==0) { if((ans|(1<<i))<=r) { ans|=1<<i; } } } cout<<ans<<'\n'; } return 0; }
G. Red Black Tree
题目:
黑色叶子下面两个必须是黑色,相邻都为黑色的叶子上面必须为黑色。n层红黑树,给k个黑色节点,补充后符合标准,这时红黑树中黑色叶子有多少个。
思路:
做法: 首先可以发现最终状态时一定是若干个不相交的三角形,且一个 底长为 m 的三角形中叶子个数为 m×(m+1) 2 。也就是说,我们只 要知道每个三角形的底长就可以算出最后的答案。 于是我们可以记录出每个点扩散到第 n 层的区间,然后对这些 区间取并集后的每一个不相交区间分别计算答案然后相加。 求区间并集可以使用差分 + 前缀和。 时间复杂度:O(n)
代码:
#include<bits/stdc++.h>
using namespace std;
int a[2000006];
int main(){
int n,k;
cin>>n>>k;
for (int i = 1; i <=k ; ++i) {
int x,y;
cin>>x>>y;
a[y]++;
a[y+n-x+1]--;
}
for (int i = 1; i <=n ; ++i) {
a[i]+=a[i-1];
}
int ans=0,ant=0;
for (int i = 1; i <=n ; ++i) {
if(a[i])ant++;
else ans+=(ant+1)*ant/2,ant=0;
}
ans+=(ant+1)*ant/2,ant=0;
cout<<ans<<endl;
}
H - Beautiful String
题意:
简要题意:给出一个字符串 s,定义一个长度为 n 且只含有不同 字符的字符串 t 是好字符串需要满足以下两个条件之一:
- 1、t1 出现在串 s 中且 t 串中的字符的大小是严格递增的。
- 2、t 串中每个字符都在 s 中出现过。
- 求不同字符串 t 的个数。
思路:
做法:简单的组合数学。
- 考虑第一种条件,我们可以记录下 s 串中出现过的字母,那么我 们可以枚举每一个出现的字母,这里我们将比当前字母大的字母 种类数记作为 p,那么这部分的答案是 Cn−1(p) 。
- 考虑第二种条件,我们可以记录下 s 串中出现过的字母,这里将 出现过的字母种类数记作为 x,那么这部分的答案是 An(x)。 但是若把这两部分的答案相加,则会多算同时满足两个条件的个 数,因此可以简单的容斥一下,将这部分的答案减掉。同时满足 两个条件的个数为 Cn(x) 。
- 为了避免取模而将字符集限制在了 18,不过注意要开 long long。
时间复杂度:O(
∑|s| + 18 × T)
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long ll a,b,c; ll AA(int n,int m){ ll aa=1; while (m--){ aa*=n--; } return aa;
} ll CC(ll n,ll m){ ll aa=1; int k=m; while (m--){ aa=n--; } ll bb=1; while (k){ bb=k; k--; } ll gg; gg=aa/bb; return gg;
} int main(){ int t; cin>>t; while (t--){ string s; int nn; cin>>s>>nn; a=0,b=0,c=0; set<char>st; for (auto i:s) { st.insert(i); } int k = st.size(); if(k>=nn){ a= AA(k,nn); c= CC(k,nn); }
for (int i = 0; i <18 ; ++i) {
if (st.count(char('a' + i)))
if(17-i>=nn-1){
b+=CC(17-i,nn-1);
}
}
cout<<a+b-c<<endl;
}
}
# [I. Digit Problem](https://codeforces.com/group/L9GOcnr1dm/contest/422378/problem/I)
## 题意:
x和y二进制表示含有a个1,b个0,z含有c个1,z=x-y成立时,输出一对x,y;
## 思路:
- 若 a > 0 且 b > 0 时,只有当 0 ≤ c ≤ a + b − 1 时是有解的。
- 下面给出一种 a > 0 且 b > 0 时的构造方式:
1. - 将 x 固定为 111...1111000...000。
2. - 若 c ≤ a 时,y 可以这么构造:
- 若 a < c ≤ a + b − 1 时,y 可以这么构造:(a-c)*1 0 c*1 (b-1)*0
- 最后对于 a = 0 或 b = 0 的情况进行特判即可。
时间复杂度:O(a + b)
## 代码:
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b,c;
cin>>a>>b>>c;
if(c>=a+b||a*b==0&&c){
cout<<"-1\n";return 0;
}
if(c==0)
cout<<string(b,'0')<<string(a,'1')<<'\n';
else if(c<=b)
cout<<string(b-c,'0')<<'1'<<string(c,'0')<<string(a-1,'1')<<'\n';
else
cout<<'1'<<string(b-1,'0')<<string(c-b,'1')<<'0'<<string(a-c+b-1,'1')<<'\n';
cout<<string(b,'0')<<string(a,'1')<<'\n';
return 0;
}
I. Digit Problem
题意:
x和y二进制表示含有a个1,b个0,z含有c个1,z=x-y成立时,输出一对x,y;
思路:
- 若 a > 0 且 b > 0 时,只有当 0 ≤ c ≤ a + b − 1 时是有解的。
- 下面给出一种 a > 0 且 b > 0 时的构造方式:
-
- 将 x 固定为 111...1111000...000。
-
- 若 c ≤ a 时,y 可以这么构造:
- 若 a < c ≤ a + b − 1 时,y 可以这么构造:(a-c)1 0 c1 (b-1)*0
- 最后对于 a = 0 或 b = 0 的情况进行特判即可。
时间复杂度:O(a + b)
代码:
#include<bits/stdc++.h> using namespace std; int main(){ int a,b,c; cin>>a>>b>>c; if(c>=a+b||a*b==0&&c){ cout<<"-1\n";return 0; } if(c==0) cout<<string(b,'0')<<string(a,'1')<<'\n'; else if(c<=b) cout<<string(b-c,'0')<<'1'<<string(c,'0')<<string(a-1,'1')<<'\n'; else cout<<'1'<<string(b-1,'0')<<string(c-b,'1')<<'0'<<string(a-c+b-1,'1')<<'\n'; cout<<string(b,'0')<<string(a,'1')<<'\n'; return 0; }
-