1.1 二进制中一的个数
原题链接
#include <iostream>
#define lowbit(i)((i)&(-i))
using namespace std;
int main()
{
int n;
cin>>n;
while(n--)
{
int res=0,m;
cin>>m;
while(m)
{
m-=lowbit(m);
res++;
}
cout<<res<<" ";
}
return 0;
}
1.2 快速幂
原题链接
#include<iostream>
using namespace std;
int main()
{
int a,b,p;
cin>>a>>b>>p;
int res=1%p;
while(b)
{
if(b&1) res=(long long)res*a%p;
a=(long long)a*a%p;
b>>=1;
}
cout<<res<<endl;
return 0;
}
1.3 64位乘法
原题链接
#include <iostream>
using namespace std;
typedef unsigned long long ull;
int main()
{
ull a,b,p;
cin>>a>>b>>p;
ull res=0;
while(b)
{
if(b&1) res=(res+a)%p;
a=a*2%p;
b>>=1;
}
cout<<res<<endl;
return 0;
}
1.4 最短Hamilton路径
原题链接
- 给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1<<20,M=20;
int n;
int f[N][M],weight[M][M];
//N为当前哪些点被用过,用20位二进制表示每个点的状态,1表示被访问过,0表示没有被访问过
//M当前停在哪些点
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>weight[i][j];
memset(f,0x3f,sizeof f);
f[1][0]=0;
for(int state=0;state<1<<n;state++)
{
for(int j=0;j<n;j++)//先枚举状态
{
if(state>>j&1)//如果state集合中第j位是1,也就是到达过这个点
{
for(int k=0;k<n;k++)
{
if(state-(1<<j)>>k&1)//state_k==state-(1<<j),为state除掉j之后的集合,且状态里面要包含k
f[state][j]=min(f[state][j],f[state-(1<<j)][k]+weight[k][j]);
}
}
}
}
cout<<f[(1<<n)-1][n-1];
return 0;
}
1.5 起床困难综合症
原题链接
给定 n,m以及n个数和该数所对应的运算,其中运算有 与、或、异或 三种,问在所有不大于m的非负整数中,对给定的n个数都按该数所对应的运算运算一遍后,能得到得最大的值是多少。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
using namespace std;
pair<string,int>a[100005];
int n,m;
int calc(int bit,int now)//假设参数为now值,填入,n次操作数的第bit位进行运算,返回预计now值
{
for(int i=0;i<n;i++)
{
int x=a[i].second>>bit&1;//取第bit位
if(a[i].first=="AND")now&=x;
else if(a[i].first=="OR")now|=x;
else now^=x;
}
return now;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
string str;
int x;
cin>>str;
scanf("%d",&x);
a[i]=make_pair(str,x);
}
int val=0,ans=0;
for(int bit=29;bit>=0;bit--)
{
int res0=calc(bit,0);
int res1=calc(bit,1);
if(res0<res1&&val+(1<<bit)<=m)//预计结果为0<1,且已经填好的更高位构成的数值加上1<<bit后不超过m,填1
{
val+=1<<bit;
ans+=res1<<bit;
}
else
ans+=res0<<bit;//其余情况,都填0
}
printf("%d",ans);
return 0;
}
位运算
题意:
编写一个程序,对于输入的正整数n,输出{0,1.....n-1}的所有子集,例如,输入3时,输出如下
{},{0},{1},{0,1},{2},{0,2},{1,2},{0,1,2}
思路:
转化为二进制,如n=3时,用三位二进制位表示,001表示0,而111表示7
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
int n;
int main()
{
cin>>n;
int m=1<<n;
for(int i=0;i<m;i++)
{
printf("(");
int j=i;
for(int k=0;k<n;k++)
if((j>>k)&1)
cout<<k;
printf(")");
}
return 0;
}