进制 & 位运算
P7442
~~众所周知,二进制有一类提需要你找规律~~
每次的1操作相当于将\(x\)这个二进制数看成一个环,并且将它旋转\(cnt \mod n\)次,\(cnt\)为总的操作次数。
而2操作就是在2操作前的\(cnt\mod n\)位上异或上一个1。
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
int cnt,n,m,op,x,tmp;
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;++i){
scanf("%lld%lld",&op,&x);
if(op==1){
tmp^=(x)*(long long)(1ll<<cnt);cnt=(cnt+1ll)%n;
}else{
int tot=x>>(n-cnt);
x=x^(tot<<(n-cnt));
printf("%lld\n",(long long)(x<<cnt)^tot^tmp);
}
}
return 0;
}
P1582
通过不断求得当前的n有多少个1,并与k判断,若小于k则符合题意,否则就将最后一位1加到贡献里去。
//求最后一位1
int lowbit(int x){
return x&-x;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long
using namespace std;
const int K=1e3+10;
int n,k;
int lowbit(int x){
return x&-x;
}
signed main(){
scanf("%lld%lld",&n,&k);
int m=n,t=0;
while(m){
m-=lowbit(m);
++t;
}
if(t<=k){
printf("0");
return 0;
}else{
int ans=0;
while(t>k){
int tmp=lowbit(n);
ans+=tmp;
n+=tmp;
int m=n;
t=0;
while(m){
m-=lowbit(m);
t++;
}
}
printf("%lld",ans);
}
return 0;
}
P1015
模拟题.
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e4+10;
int n;
struct HP{
int p[N],len;
void clear1(){
memset(p,0,sizeof p);
len=1;
}
void read1(){
memset(p,0,sizeof p);
len=0;
p[0]=1;
char ch=getchar();
int x=0,f=1;
while(!(ch<='9' && ch>='0' || ch<='F' && ch>='A' || ch<='f' && ch>='a')){
ch=getchar();
}
while((ch<='9' && ch>='0' || ch<='F' && ch>='A' || ch<='f' && ch>='a')){
++len;
if(n==16){
if(ch<='F' && ch>='A'){
p[len]=ch-'A'+10;
}else if(ch<='f' && ch>='a'){
p[len]=ch-'a'+10;
}else p[len]=ch-'0';
}else p[len]=ch-'0';
ch=getchar();
}
for(int i=1;i<=len/2;++i){
swap(p[i],p[len-i+1]);
}
}
void write1(){
for(int i=len;i>=1;--i){
printf("%d",p[i]);
}
putchar('\n');
}
};
HP operator +(const HP &a,const HP &b){
HP c;
c.clear1();
int la=a.len,lb=b.len,lc=max(la,lb),x=0;
for(int i=1;i<=lc;++i){
c.p[i]=a.p[i]+b.p[i]+x;
x=c.p[i]/n;
c.p[i]%=n;
}
if(x)c.p[++lc]=x;
c.len=lc;
return c;
}
HP new1(HP a){
HP b;
b.clear1();
int la=a.len;
b.len=la;
for(int i=1;i<=la;++i){
b.p[la-i+1]=a.p[i];
}
a=a+b;
return a;
}
bool check(HP a){
bool flag=true;
for(int i=1;i<=a.len/2;++i){
if(a.p[i]!=a.p[a.len-i+1])flag=false;
}
return flag;
}
int main(){
scanf("%d",&n);
HP a;
a.read1();
int cnt=0;
while(!check(a) && cnt<=31){
a=new1(a);
cnt++;
}
if(cnt>=31)printf("Impossible!");
else printf("STEP=%d",cnt);
return 0;
}
P2852
这道题时\(hash\)优化的字符串表示法,将每个字符串看成一个\(C\)进制数即可,并将它\(mod\)上一个大质数\(P\),因为我们用前缀和的思想表示每一个子串,所以对于\(n\)个数的序列总共只有\(n\)个字符串,如果\(P\)足够大并且是质数就不会出现状态重复的情况。~~如果有,就换一个更♂大♂的~~
代码在\(hash\)优化里有。
P3760
~~位运算好题~~
对于所有复杂的位运算,我们有个常用的\(Trick\),就是将每个数拆位,每个数只用记录\(O(\log n)\)个位.
对于枚举的位数\(v\),我们只需要统计有多少个\(s\)满足:
\((s[j]-s[i]>>v)&1==1\)即可。
那么可以开两个树状数组,记录第\(v\)位分别为0或1的状态。
对于当前枚举到的\(s[i]\):
1) 第\(v\)位为1,那只需要找到第\(v\)位之前比他小且0的个数或比他大且1的个数。
2) 第\(v\)位为0,那只需要找到第\(v\)位之前比他大且0的个数或比他小且1的个数。
#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e5+10,C=1e6+10;
int s[N],a[N],f[C][2];
int n,maxn,ans;
void change(int i,int x,int d){
while(x<C)f[x][i]+=d,x+=lowbit(x);
}
int sum(int i,int x){
int ans=0;
while(x>0)ans+=f[x][i],x-=lowbit(x);
return ans;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]),s[i]=s[i-1]+a[i],maxn=max(maxn,s[i]);
for(int v=0;v<=20;++v){
if((1<<v)>maxn)break;
int cnt=0;
memset(f,0,sizeof f);
change(0,1,1);
for(int i=1;i<=n;++i){
int tmp=s[i]&((1<<v)-1),type=(s[i]>>v)&1;
if(type)cnt+=sum(1,C-1)-sum(1,tmp+1)+sum(0,tmp+1);
else cnt+=sum(0,C-1)-sum(0,tmp+1)+sum(1,tmp+1);
change(type,tmp+1,1);
}
if(cnt%2)ans|=(1<<v);
}
printf("%lld",ans);
return 0;
}