The 2020 ICPC Asia Taipei-Hsinchu Site Programming Contest-C題 Pyramid (思維,遞推,規律)
題意:
一個n*n的矩陣,取其上三角矩陣,每個點的初值爲L,左上角爲起點,每次在起點放入一個球,如果當前點爲L,則向下走,若爲R,則向右走,則之後L會變成R,或R變成L。
問第k個球最後落入哪裏。
思路:
解題關鍵:
對於一個開關,若有x個小球經過此處,顯然它會把 \(\lceil\frac{x}{2}\rceil\)個小球向左傳送,會把\(\lfloor\frac{x}{2}\rfloor\)個小球向右傳送。
由此我們可以自頂向下推出每一層的每個開關處有多少小球經過。
每一個開關會由其上方的1~2個開關轉移過來,所以我們只需要開\(dp[2][n]\)進行奇偶滾動數組dp求解。
如果我們知道了在一個小球到達某開關之前此處有多少小球經過,之前有奇數次經過該開關那麼本次就向右走,之前有偶數次經過該開關那麼本次就向左走,由此就能得到小球在這個開關的走向。
我們先求出前k-1個小球走過後每一個開關被走的次數,之後就能方便的求出第k個小球在每一層的走向,進而得到最後的結果。
代碼:
#include <bits/stdc++.h>
using namespace std;
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') { fh = -1; } c = getchar();} while (c >= '0' && c <= '9') { tmp = tmp * 10 + c - 48, c = getchar(); } return tmp * fh;}
int n;
int val[2][10010];
int main()
{
int t;
t = readint();
while (t--) {
n = readint();
int k = readint();
if(n==1)
{
printf("0\n");
continue;
}
val[0][0]=k-1;
int ans=0;
if(val[0][0]&1)
ans++;
for(int i=1;i<n-1;++i)
{
int last=0;
for(int j=0;j<i;++j)
{
val[i%2][j]=last+(val[(i-1)%2][j]+1)/2;
last=val[(i-1)%2][j]/2;
}
val[i%2][i]=last;
if(val[i%2][ans]&1)
{
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}