题目大意:
最初的数组长度为2×n2 \times n2×n,包含[1,n][1,n][1,n]这nnn个数字,第i个数字在第2×i−12 \times i-12×i−1的位置上。
每次将最后一个非空的位置,移到最后一个空位置上。
当所有位置全部在[1,n][1,n][1,n]时,停止
给出mmm次询问,每次询问,算法停止后第xxx位置的数字是哪个数字:
不懂就看图
题目思路:
卡的心态裂开…
思维题能不能做出来啊…
考虑最终状态逆向推到出最初的状态,假设xxx的位置pospospos是奇数,那么这个奇数就不会动了,因为移动必定会移动到一个偶数格子上,所以当位置是奇数时,就说明已经到达了初始状态。
那么根据现在的位置pospospos推出上一轮pospospos应该在的位置:
- 首先,pos左边包含pos一定有(pos+1)/2(pos+1)/2(pos+1)/2个数
- 右边的数一定紧挨着有(n−{(pos+1)/2})(n-\{ (pos+1)/2 \})(n−{(pos+1)/2})个数
- 并且他一定是从末尾移动过来的,所以上一轮的位置就是:pos+(n−{(pos+1)/2})+1pos + (n-\{ (pos+1)/2 \})+1pos+(n−{(pos+1)/2})+1
这样当pospospos是奇数时退出循环,就是最后的位置了…
思维题一定要注意:
逆向推导
多画总结规律
Code:
/*** keep hungry and calm CoolGuang! ***/
//#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const int maxn = 1e6+700;
const int M = 1e6+8;
const int mod= 1e9+7;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int main(){
read(n);read(m);
for(int i=1;i<=m;i++){
ll x;read(x);
while(x%2 == 0){
ll opx = x/2+1;///左边的数量
x = (x+(n-opx)+1);
}
printf("%lld\n",(x+1)/2);
}
return 0;
}
/***
1
24
133321333
***/