zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 091F

    AtCoder Regular Contest 091F - Strange Nim

    题目大意

    • N N N堆石子,每堆有 A i A_i Ai颗,两个人轮流取,每次选择其中一堆,当其剩下石子数为 x x x时,取的石子数不能超过 x / k x/k x/k下取整,每堆的 k k k是一个定值,不能取的人为负。
    • N ≤ 200 N≤200 N200
    • A i , k i ≤ 1 0 9 A_i,k_i≤10^9 Ai,ki109

    题解

    • 显然可以先计算出对于不同 k k k的每个状态的SG函数值,从 0 0 0开始打个表出来,
    • 把这些数 k k k个一行,会发现第一列从 0 0 0开始依次递增 1 1 1,第一行全为 0 0 0,当把第一列的数全部删去后,剩下的数也满足这个规律,
    • 那么一开始先把 A i A_i Ai加一,再这样一直删下去就可以求出当前 A i A_i Ai的函数值。
    • 一开始以为这样就可以过了,其实发现是会TLE的,
    • 有可能 A i A_i Ai特别大,但 A i / k i A_i/k_i Ai/ki也特别大,以至于每次只能删去很少的几个数,需要重复操作很多遍,
    • 那么直接考虑一次性多删一些。
    • 每次相当于给 A i A_i Ai减去 ( A i − 1 ) / k (A_i-1)/k (Ai1)/k下取整,当 ( A i − 1 ) / k (A_i-1)/k (Ai1)/k下取整的值没变时,每次减去的数值就是一样的,那么直接就算最多可以先重复删多少个这个值即可。

    代码

    #include<cstdio>
    using namespace std;
    int solve(int x, int k) {
    	if(x <= k) return 0;
    	if((x - 1) % k == 0) return (x - 1) / k;
    	int d = (x - 1) / k * k + 1, t = (x - 1) / k + 1;
    	return solve(x - ((x - 1 - d) / t + 1) * t, k);
    }
    int main() {
    	int n, s = 0, x, k;
    	scanf("%d", &n);
    	while(n--) {
    		scanf("%d%d", &x, &k);
    		s ^= solve(x + 1, k);
    	}
    	if(s) printf("Takahashi"); else printf("Aoki");
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    poj 3280 Cheapest Palindrome(区间DP)
    POJ 2392 Space Elevator(多重背包)
    HDU 1285 定比赛名次(拓扑排序)
    HDU 2680 Choose the best route(最短路)
    hdu 2899 Strange fuction (三分)
    HDU 4540 威威猫系列故事――打地鼠(DP)
    HDU 3485 Count 101(递推)
    POJ 1315 Don't Get Rooked(dfs)
    脱离eclipse,手动写一个servlet
    解析xml,几种方式
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910017.html
Copyright © 2011-2022 走看看