1.题目链接
https://codeforces.com/gym/102835/problem/C
2.题意
一个金字塔形状的网格,从塔尖向下放小球,每个点有一个开关可以使得小球在此处向左或者向右,初始状态下所有开关均向左。当小球经过一个开关会使得开关的状态翻转。给定金字塔的层数n,求第k个小球到塔底时位于哪一列。
3.题解
对于一个开关,若有x个小球经过此处,显然它会把
⌈
x
2
⌉
\lceil\frac{x}{2}\rceil
⌈2x⌉个小球向左传送,会把
⌊
x
2
⌋
\lfloor\frac{x}{2}\rfloor
⌊2x⌋个小球向右传送。由此我们可以自顶向下推出每一层的每个开关处有多少小球经过。知道了每个开关处有多少小球经过有什么用呢?如果我们知道了在一个小球到达某开关之前此处有多少小球经过,之前有奇数个经过那么本次就向右,之前有偶数个那么本次就向左,由此就能得到小球在这个开关的走向。
所以我们可以先求出前k-1个小球的分布结果,之后就能方便的求出第k个小球在每一层的走向,进而得到最后的结果。
比如我们要求n=5,k=16的结果。我们可以先求出前15个小球的分布状态,再据此求得最终答案。
时间复杂度 O ( n 2 ) O(n^2) O(n2)
4.代码
#include<stdio.h>
#define MAXN 10005
int T,n,k;
int main()
{
scanf("%d",&T);
while(T--)
{
int v[2][MAXN];
scanf("%d%d",&n,&k);
if(n==1)
{
puts("0");
continue;
}
v[0][0]=k-1;
int ans=0;
if(v[0][0]%2) ans++;
for(int i=1;i<n-1;i++)
{
int cnt=0;
int last=0;
for(int j=0;j<i;j++)
{
v[i%2][cnt++]=last+(v[(i-1)%2][j]+1)/2;
last=v[(i-1)%2][j]/2;
}
v[i%2][cnt]=last;
if(v[i%2][ans]%2) ans++;
}
printf("%d\n",ans);
}
return 0;
}