由K倍動態減法聯想到的一類博弈問題 HDOJ 2580

來源:互聯網
上載者:User

給一堆石子,數量為n,先取的人最多能取n - 1個,之後每次最多能取上次對手取的石子的數量的k倍

當k = 1時必敗數列為(1, 2, 4, 8 ……),當n的二進位中不止一位為1時,我們每次取n的二進位的最低一非0位元量,那麼對手就絕對不能取完(因為高位的是地位的至少二倍),而對手不管取x為多少,假設x的最高位1為w,那麼取後剩餘石子n的w位或者w以下一定有1,那麼我們就又可以取最低一位1了,依次進行,只有自己才能勝利。相反n的二進位只有一位,而我們又不能取完,相當於自己不能取最後一位非0位,對手就能勝。

當k = 2時必敗數列為(斐波那契數列)(1,2, 3, 5, 8……),每個n都可以用數列中的不相鄰數字相加得到,假設有至少兩個數字(從小到大排序)(x1, x2……)相加,我們每次取最小的x1,因為x1,x2不相鄰,及x1,x2至少相隔1個數字,觀察斐波那契數列:隔1數位兩個數字大的是小的的至少兩倍。那麼對手絕對不能取完x2,對手取完後又得到一數字n1,依次進行,最後只有可能自己拿完石子。如果n及為數列中的數字,那麼該n只能由一個x1相加組成,這時候我們不能取完,及不能取走最小的數字,相當於對手的勝局。

當k = n時,我們就要構造自己的數列

首先失敗點為數列array(1),最大相加能組成的為max(1)

因為前面的array【i】最多能組成max【i】,max【i 】 + 1沒法由數列中的數字相加組成

我們可以建立一個點,array【i + 1】 = max 【i】+ 1,解決問題;

新加了一個節點後最大能組成的數字應該為max【j】 + array【i + 1】;

因為要滿足組成數字n的所有數字(x1, x2, x3……)相差至少k倍,所以array【j】滿足array【j】 * k < array【i + 1】;

我們求的是最大能表示的數字,這時候只需要j足夠大就可以了

很明顯,j是隨著失敗數列中的數位增多而增大的,由此最佳化演算法,避免逾時

HDOJ 2580 My Code

#include<stdio.h>__int64 max[3000001], array[3000001];int main(){__int64 n, k, i, j;int cases, ca = 0;scanf("%d", &cases);while(cases --){scanf("%I64d%I64d", &n, &k);array[0] = 0;max[1] = 1;array[1] = 1;i = 1;j = 1;while(array[i] < n){i ++;array[i] = max[i - 1] + 1;while(array[j] * k < array[i])j ++;j --;max[i] = max[j] + array[i];if(i == 100000)printf("");}if(array[i] == n)printf("Case %d: lose\n", ++ca);else{while(1){if(n == array[i]){printf("Case %d: %I64d\n", ++ca, array[i]);break;}if(n > array[i]){n -= array[i];}else{i --;}}}}return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.