c Strange Test
也就3种情况:1.a直接加到b,2.a加到某个数之后或到b,3.b加到某个数a或到b;所以这样来枚举就可以了
(2条消息) 768、C. Strange Test(与运算) 769、C - And Matching(或运算)_linglingnana的博客-CSDN博客
#include<bits/stdc++.h>
#define ll long long
typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
/*void init_set(){
for(int i=1;i<=n;i++) s[i]=i,hei[i]=0;
}
int find_set(int x){
if(x!=s[x]) s[x]=find_set(s[x]);
return s[x];
}*/
/*void union_set(int x,int y){
x=find_set(x);
y=find_set(y);
if(hei[x]==hei[y]){
hei[x]=hei[x]+1;
s[y]=x;
}
else{
if(hei[x]<hei[y]) s[x]=y;
else s[y]=x;
}
}*/
ll t,a,b;
int main(){
//freopen("in.txt","r",stdin);
cin>>t;
while(t--){
cin>>a>>b;
if((a|b)==b){cout<<1<<endl;continue;}
ll ans=b-a;
for(int i=1;i+1<=ans;i++){
if(((a+i)|b)==b||((b+i)|a)==b+i) ans=i+1;
}
cout<<ans<<endl;
}
return 0;
}
CF1594D The Number of Imposters 并查集
我们考虑每一条信息可以告诉我们什么:
- 假设 A 说 B 是老实人,那么:
- 如果 A 是老实人,则 B 也是老实人。
- 如果 A 是骗子,由于 B 不是老实人,所以 B 必然为骗子。
- 如果 A 说 B 是骗子:
- A 说实话,B 是骗子。
- A 说谎,B 是老实人。
同样的,如果 A 说 B 是老实人,而 B 确实是老实人,则 A 说的是实话,也是老实人。
用并查集来维护这个规则,令(1,n)是诚实的人,(n+1,2n)是骗子
做统计的时候考虑每个集合的代表是老实人/骗子的情况下,哪种老实人数量更多,累加起来就是答案。
CF1594D 题解 - PragmaGCC 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
/*void init_set(){
for(int i=1;i<=n;i++) s[i]=i,hei[i]=0;
}
int find_set(int x){
if(x!=s[x]) s[x]=find_set(s[x]);
return s[x];
}*/
/*void union_set(int x,int y){
x=find_set(x);
y=find_set(y);
if(hei[x]==hei[y]){
hei[x]=hei[x]+1;
s[y]=x;
}
else{
if(hei[x]<hei[y]) s[x]=y;
else s[y]=x;
}
}*/
char s[200005];
int t,n,m,fa[400005],siz[400005];
int findd(int x){
if(x==fa[x]) return x;
fa[x]=findd(fa[x]);
siz[fa[x]]+=siz[x];
siz[x]=0;
return fa[x];
}
void mergee(int x,int y){
int fx=findd(x),fy=findd(y);
if(fx==fy) return;
siz[fx]+=siz[fy];siz[fy]=0;
fa[fy]=fx;
}
int main(){
//freopen("in.txt","r",stdin);
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
for(int i=1;i<=n<<1;i++) fa[i]=i,siz[i]=i<=n;
for(int i=1,x,y;i<=m;i++){
cin>>x>>y>>s;
if(s[0]=='c') mergee(x,y),mergee(x+n,y+n);
else mergee(x,y+n),mergee(y,x+n);
}
int ans=0;
for(int i=1;i<=n;i++){
if(findd(i)==findd(i+n)){ans=-1;break;}// 一个人既诚实又说谎,出现矛盾
ans+=max(siz[findd(i)],siz[findd(i+n)]);
siz[findd(i)]=siz[findd(i+n)]=0;
}
cout<<ans<<endl;
}
return 0;
}
p6691
和上一个题类似,但比上一题难,话说难为啥这题黄上一个题绿。。。
但是这里有两种对应关系——真话和假话,真话边连接的两点是同对同错的,否则无解。假话边则相反。所以我们的边要带一个边权,之后通过遍历将边的信息转移到点上(哪些点同对错,哪些点对错性相反)边权为 0 表示为真话边,边权为 1 表示为假话边。
为什么要这样设置呢? 按题目中 1 对应真不好吗?
这里的信息要进行传递,A说B是假,B说C是假,那么A和C就是同对同错的了。所以我想到一个神奇的位运算——异或(在c++ 中用 ^ 表示)。
0 ^ 0 = 0 真边 + 真边 = 真边
1 ^ 0 = 1 假边 + 真边 = 假边
1 ^ 1 = 0 假边 + 假边 = 真边
上面源自题解 P6691 【选择题】 - llzzxx712 的博客 - 洛谷博客 (luogu.org)
然后这个规则对应的代码中的r数组,来处理结点与上一个结点之间的关系,然后代码里也放注释了
#include<bits/stdc++.h>
#define ll long long
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
/*void init_set(){
for(int i=1;i<=n;i++) s[i]=i,hei[i]=0;
}
int find_set(int x){
if(x!=s[x]) s[x]=find_set(s[x]);
return s[x];
}*/
/*void union_set(int x,int y){
x=find_set(x);
y=find_set(y);
if(hei[x]==hei[y]){
hei[x]=hei[x]+1;
s[y]=x;
}
else{
if(hei[x]<hei[y]) s[x]=y;
else s[y]=x;
}
}*/
int f[2000006],r[2000006],num[2000005][2],n;
int ans1,ans2,x,op,tot=1;
int findd(int x){
if(f[x]==x) return f[x];
int t=f[x];
f[x]=findd(f[x]);
r[x]=(r[t]+r[x])%2;//相当于在做异或
return f[x];
}
void mergee(int i,int x,int op){
int tmp=findd(i);
f[tmp]=findd(x);
r[tmp]=(r[i]+r[x]+op+1)%2;//加1是为了对应思路中的0为真,1为假
return;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>n;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=n;i++){
cin>>x>>op;
if(findd(i)!=findd(x))
mergee(i,x,op);
else{
if((r[i]+r[x])%2!=(op+1)%2){//异或值不相同,第一条边共和第三条边权值不等,说明冲突
cout<<"No answer"<<endl;
return 0;
}
}
}
for(int i=1;i<=n;i++)
num[findd(i)][r[i]]++;//统计答案的个数
for(int i=1;i<=n;i++){
if(findd(i)==i){
tot=tot*2%998244353;
ans1+=max(num[i][1],num[i][0]);//累计加最大的
ans2+=min(num[i][1],num[i][0]);//累计加最小的
}
}
cout<<tot<<endl<<ans1<<endl<<ans2<<endl;
return 0;
}
p3374 树状数组 单点修改区间查询模板
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
int n,m,t[500005];
void add(int x,int y){//树状数组单点修改
for(int i=x;i<=n;i+=lowbit(i))
t[i]+=y;
}
int getsum(int x){//树状数组区间查询
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=t[i];
return ans;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>n>>m;
int a;
for(int i=1;i<=n;i++){
cin>>a;add(i,a);
}
int x,y;
while(m--){
cin>>a>>x>>y;
if(a==1)
add(x,y);
else cout<<getsum(y)-getsum(x-1)<<endl;
}
return 0;
}
p4939 树状数组 区间修改 单点查询模板
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1000000007;
const double eps=1e-11;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,m,x,y,op,a[10000007],t[10000007];
void add(ll x,ll y){
for(int i=x;i<=n;i+=lowbit(i))
t[i]+=y;
}
void rangeadd(ll l,ll r,ll x){
add(l,x);add(r+1,-x);
}
ll ask(ll x){
ll res=0;
for(int i=x;i;i-=lowbit(i))
res+=t[i];
return res;
}
int main(){
// freopen("in.txt","r",stdin);
n=read();m=read();
for(int i=1;i<=n;i++) t[i]=0;
while(m--){
op=read();
if(op){x=read();cout<<ask(x)<<endl;}
else{x=read();y=read();rangeadd(x,y,1);}
}
return 0;
}
p3372线段树模板
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll a[100005],n,m,x,y,k,q;
struct segtree{
ll val,lazy;
}tree[100005<<2];
void pushup(ll rt){tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;}
void build(ll l,ll r,ll rt){
tree[rt].lazy=0;
if(l==r){
tree[rt].val=a[l];
return;
}
ll m=l+r>>1;
build(l,m,rt*2);
build(m+1,r,rt*2+1);
pushup(rt);
}
//L,R为目标区间,l,r为当前区间,C是要加的值,rt是当前数组下标
void pushdown(ll rt,ll ln,ll rn){
if(tree[rt].lazy){//下推标记
tree[rt<<1].lazy+=tree[rt].lazy;
tree[rt<<1|1].lazy+=tree[rt].lazy;
tree[rt<<1].val+=tree[rt].lazy*ln;
tree[rt<<1|1].val+=tree[rt].lazy*rn;
tree[rt].lazy=0;//置为0,以免以后访问时造成混乱
}
}
void update(ll L,ll R,ll C,ll l,ll r,ll rt){
if(L<=l&&r<=R){
tree[rt].val+=C*(r-l+1);
tree[rt].lazy+=C;
return;
}
ll m=l+r>>1;
pushdown(rt,m-l+1,r-m);//m-l+1,r-m都是区间大小,下推标记
if(L<=m) update(L,R,C,l,m,rt<<1);
if(R>m) update(L,R,C,m+1,r,rt<<1|1);
pushup(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
if(L<=l&&r<=R) return tree[rt].val;
if(L>r||R<l) return 0;
ll m=l+r>>1;
pushdown(rt,m-l+1,r-m);//下推以后才能查询子节点,不然子节点是未改变的状态
return query(L,R,l,m,rt<<1)+query(L,R,m+1,r,rt<<1|1);
}
int main(){
//freopen("in.txt","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,n,1);
while(m--){
cin>>q;
if(q==1){
cin>>x>>y>>k;
update(x,y,k,1,n,1);
}
else{
cin>>x>>y;
ll ans=query(x,y,1,n,1);
cout<<ans<<endl;
}
}
return 0;
}
p3373 线段树区间修改加法与乘法模板
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void write(int x) {//快写
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll a[100005],n,m,p,x,y,k,q;
struct segtree{
ll val,lazy[3];
}tree[100005<<2];
void pushup(ll rt){tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%p;}
void build(ll l,ll r,ll rt){
tree[rt].lazy[1]=0;
tree[rt].lazy[2]=1;
if(l==r){
tree[rt].val=a[l];
return;
}
ll m=l+r>>1;
build(l,m,rt*2);
build(m+1,r,rt*2+1);
pushup(rt);
}
//L,R为目标区间,l,r为当前区间,C是要加的值,rt是当前数组下标
void pushdown(ll rt,ll ln,ll rn){
//下推到子节点
tree[rt<<1].lazy[2]=(tree[rt<<1].lazy[2]*tree[rt].lazy[2])%p;
tree[rt<<1|1].lazy[2]=(tree[rt<<1|1].lazy[2]*tree[rt].lazy[2])%p;
tree[rt<<1].lazy[1]=(tree[rt<<1].lazy[1]*tree[rt].lazy[2]+tree[rt].lazy[1])%p;
tree[rt<<1|1].lazy[1]=(tree[rt<<1|1].lazy[1]*tree[rt].lazy[2]+tree[rt].lazy[1])%p;
//儿子的值=此刻儿子的值*爸爸的乘法lazytag+儿子的区间长度*爸爸的加法lazytag
tree[rt<<1].val=(tree[rt<<1].val*tree[rt].lazy[2]+tree[rt].lazy[1]*ln)%p;
tree[rt<<1|1].val=(tree[rt<<1|1].val*tree[rt].lazy[2]+tree[rt].lazy[1]*rn)%p;
//把父节点的值初始化
tree[rt].lazy[1]=0;
tree[rt].lazy[2]=1;
}
void update1(ll L,ll R,ll C,ll l,ll r,ll rt){//乘法更新
ll m=l+r>>1;
if(R<l||L>r) return;
if(L<=l&&r<=R){
tree[rt].val=(tree[rt].val*C)%p;
tree[rt].lazy[1]=(tree[rt].lazy[1]*C)%p;
tree[rt].lazy[2]=(tree[rt].lazy[2]*C)%p;
return;
}
pushdown(rt,m-l+1,r-m);
if(L<=m) update1(L,R,C,l,m,rt<<1);
if(R>m) update1(L,R,C,m+1,r,rt<<1|1);
pushup(rt);
}
void update2(ll L,ll R,ll C,ll l,ll r,ll rt){//加法更新
ll m=l+r>>1;
if(R<l||L>r) return;
if(L<=l&&r<=R){
tree[rt].val=(tree[rt].val+C*(r-l+1))%p;
tree[rt].lazy[1]=(tree[rt].lazy[1]+C)%p;
return;
}
pushdown(rt,m-l+1,r-m);
if(L<=m) update2(L,R,C,l,m,rt<<1);
if(R>m) update2(L,R,C,m+1,r,rt<<1|1);
pushup(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
if(L<=l&&r<=R) return tree[rt].val;
if(L>r||R<l) return 0;
ll m=l+r>>1;
pushdown(rt,m-l+1,r-m);//下推以后才能查询子节点,不然子节点是未改变的状态
return (query(L,R,l,m,rt<<1)+query(L,R,m+1,r,rt<<1|1))%p;
}
int main(){
// freopen("in.txt","r",stdin);
cin>>n>>m>>p;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,n,1);
while(m--){
cin>>q;
if(q==1){
cin>>x>>y>>k;
update1(x,y,k,1,n,1);
}
else if(q==2){
cin>>x>>y>>k;
update2(x,y,k,1,n,1);
}
else{
cin>>x>>y;
ll ans=query(x,y,1,n,1);
cout<<ans%p<<endl;
}
}
return 0;
}