先判断 1 出现的次数 cnt 的奇偶,再判断其二进制第 0 位是否为 1.
如果是偶数,要变为奇数,操作次数+1.
如果第 0 位为 1,那么需要操作 2*cnt-1
次;否则操作 2*cnt+1
次。
加快读快输 (网上抄的板子)
inline int read()
{
int x=0; //输出结果;
char c=getchar(); //先读个字符;
while(c<'0'||c>'9') c=getchar(); //读入非数字字符;
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); //读入数字;
return x;
}
void print(int x)
{
char P[10005];int w=0;
if(x<0) putchar('-'),x=-x;//特判负数
if(x==0) putchar('0');
while(x) P[++w]=x%10+'0',x/=10;//分离各位
for(int i=w; i>=1; i--) putchar(P[i]);//逆序输出
puts("");
}
void check(int n)
{
string s;
int sum=0;
while(n)
{
if(n&1) s+='1',sum++;
else s+='0';
n >>= 1;
}
cnt=0;
if(sum%2==0)
{
cnt++;
sum--;
}
if(s[0]=='1') cnt+=sum*2-1;
else cnt+=sum*2+1;
print(cnt);
}
int main(){
cin>>T;
while(T--)
{
n=read();
check(n);
}
return 0;
}
因为n最多到10,所以直接求全排列。
两种方式:
1.dfs,遍历每一位看放什么数,每遍历一层判断当前排列是否满足,不满足及时return。
2.nextmutation函数:暴力判断即可。
const int N = 200010, mod = 1e9 + 7;
int T, n, m, a[N];
int pre[N],ans;
int f[N];
void dfs(int u)
{
for(int i=1;i<=n;i++){
if(a[pre[i]]==0) continue;
if(a[pre[i]]<a[i]) return;
}
if(u==n+1){
ans++;return;
}
for(int i=1;i<=n;i++)
{
if(f[i]) continue;
a[u]=i;
f[i]=1;
dfs(u+1);
f[i]=0;
a[u]=0;
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>pre[i];
dfs(1);
cout<<ans;
return 0;
}
nextmutation函数板子:
int main(){
cin>>n;
for(int i=1;i<=n;i++) a[i]=i;
do
{
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}while(next_permutation(a+1,a+n+1));
return 0;
}
每个人的范围为(ai-k,ai+k),最终选一个数,满足的人最多。
将每个人的所在的范围中的所有数+1——差分标记,最终前缀和还原。
判断哪个数最大便是满足的最多人数。
const int N = 2000010, mod = 1e9 + 7;
int T, n, m, a[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;cin>>x;
x+=1000000;
a[x-m]++,a[x+m+1]--;
}
int ans=0;
for(int i=0;i<=2000000;i++){
a[i]+=a[i-1];
ans=max(ans,a[i]);
}
cout<<ans;
return 0;
}
最大值最小,二分答案。
check:
如果当前值和前一值不同或者人数达到mid,就新开一组。
如果最终的组数不超过m,则满足,继续往前分。
(既然分不超过m组就满足每组的最多人数不超过mid,那么分m组肯定更满足。)
const int N = 200010, mod = 1e9 + 7;
int T, n, m, a[N];
bool check(int mid)
{
int cnt=0,ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]!=a[i-1]||cnt==mid) ans++,cnt=1;
else cnt++;
}
if(ans<=m) return 1;
return 0;
}
int main(){
cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(!mp[a[i]]) cnt++,mp[a[i]]=1;
}
if(cnt>m){
cout<<-1;return 0;
}
sort(a+1,a+n+1);
int l=1,r=n;
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<l;
return 0;
}
这里 有二分答案的详解和典例。
两种方法:
1.bfs计算最少操作次数,第一次到达的便是最少的。
2.建边跑最短路。
1.bfs:
void bfs()
{
queue<int> que;
que.push(1);
mp[1]=0;
while(que.size())
{
int x=que.front();que.pop();
if(x>0){
for(int i=x+1;i<=min(n,x+a[x]);i++)
{
if(!mp.count(i)) que.push(i),mp[i]=mp[x]+1;
}
}
else{
for(int i=1;i<=max(1,x+a[x]);i++){
if(!mp.count(i)) que.push(i),mp[i]=mp[x]+1;
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
bfs();
if(mp[n]) cout<<mp[n];
else cout<<-1;
return 0;
}
2.dijkstra最短路:
const int N = 2010, mod = 1e9 + 7;
int T, n, m, a[N];
int f[N];
int e[N*N],ne[N*N],h[N],idx;
int dist[N];
void add(int x,int y){
e[idx]=y,ne[idx]=h[x],h[x]=idx++;
}
void dij()
{
mem(dist,0x3f);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII> > que;
que.push({0,1});
while(que.size())
{
int x=que.top().se;que.pop();
if(f[x]) continue;
f[x]=1;
for(int i=h[x];i!=-1;i=ne[i])
{
int tx=e[i];
if(dist[tx]>dist[x]+1){
dist[tx]=dist[x]+1;
que.push({dist[tx],tx});
}
}
}
}
int main(){
cin>>n;
mem(h,-1);
for(int i=1;i<=n;i++)
{
int x;cin>>x;
if(x>0){
for(int j=i+1;j<=i+x;j++) add(i,j);
}
else{
for(int j=1;j<=max(1,i+x);j++) add(i,j);
}
}
dij();
if(dist[n]!=0x3f3f3f3f) cout<<dist[n];
else cout<<-1;
return 0;
}
待更。。