I was struggling for the same test case, and finally went through. I thought maybe many people made the same mistake, so I attached my code below to explain the possible error. The key line has been commented and highlighted. If this line is missing, you will not pass the test case (10, 40). test case (10, 40)

class Solution {
public:
bool canIWin(int maxChoosableInteger, int desiredTotal) {
int n = maxChoosableInteger, tar = desiredTotal, sum = 0;
for (int i = 1; i <= n; ++i) sum += i;
// this case is impossible
if (tar > sum) return false;
// used[i] marks whether i+1 was used;
// the key of dp is binary format of int, representing which numbers have been used
unordered_map<int, bool> dp;
vector<int> used(n, 1);
return helper(used, dp, 0, tar);
}
private:
bool helper(vector<int>& used, unordered_map<int, bool>& dp, int key, int tar) {
if (dp.count(key)) return dp[key];
int n = used.size();
// search backward, greedy choice
for (int i = n-1; i >= 0; --i) {
if (used[i]) {
// can win
if (i+1 >= tar) {
dp[key] = true;
return true;
}
// backtracking
used[i] = 0;
// if next state key|(1<<i) results in lose, this state can win;
// however, if next state can win, this state is not necessary to lose; we need search all choices.
if (!helper(used, dp, key|(1<<i), tar-i-1)) {
dp[key] = true;
// if next line commented, it won't pass test case (10, 40)
// I thought if it returns true, I don't have to reset used[i]; However, when it is true for current state,
// backtracking or DFS/dp for previous state will continue searching, so it is necessary to reset used[i]
used[i] = 1;
return true;
}
used[i] = 1;
}
}
dp[key] = false;
return false;
}
};