题解:
第一题:异或的老套路,按位算贡献,统计某一位有多少个数为1,就用数位DP好了;
#include<bits/stdc++.h> using namespace std; const int M = 1e6; #define ll long long const ll mod = 1e9 + 7; int L, R, dp[35][2]; int bin[33], cnt[33], digit[33]; inline ll moc(ll a){return a >= mod ? a - mod : a;} void solve1(){ ll ans = 0; for(int i = L; i <= R; i++) for(int j = L; j <= R; j++) ans = moc(ans + (i ^ j) % mod); printf("%lld ", ans); } int dfs(int dep, int s, bool f, int sum){ if(!dep) return sum; if(!f && dp[dep][sum] != -1) return dp[dep][sum]; int i = f ? digit[dep] : 1; int tmp = 0; for(; i >= 0; i--){ if(dep == s && i) tmp += dfs(dep - 1, s, f & (i == digit[dep]), sum + 1); else tmp += dfs(dep - 1, s, f & (i == digit[dep]), sum); } if(f) return tmp; return dp[dep][sum] = tmp; } void get(int x, ll f){ int d = 0; if(x < 0) return; while(x){ digit[++d] = x & 1; x >>= 1; } for(int i = 1; i <= 31; i++){ memset(dp, -1, sizeof(dp)); cnt[i] += f * dfs(d, i, 1, 0); } } void solve3(){ memset(cnt, 0, sizeof(cnt)); get(L-1, -1); get(R, 1); ll ans = 0; ll cc = R - L + 1; for(int j = 1; j <= 31; j++) ans = moc(ans + 1LL*bin[j] * cnt[j] % mod * (cc - cnt[j]) * 2 % mod); printf("%lld ", ans); } int main(){ freopen("xor.in","r",stdin); freopen("xor.out","w",stdout); int T; scanf("%d", &T); bin[1] = 1; for(int i = 2; i <= 31; i++) bin[i] = bin[i-1] << 1; while(T--){ scanf("%d%d", &L, &R); solve3(); } }
第二题:博弈论;
两堆石子:
上面的表总结一下就是:我们知道(x, y)是必输状态,那么(x, z) z != y一定是必赢状态;
分类讨论: z>y,我一定可以一步转移到(x,y) ; z<y, 如果(x,z)必输,那么(x,y)就可以转移到他,成为必赢状态,与已知条件矛盾;
所以一个x,对应一个y, y‘'-x''的值相同时时,都是必赢状态;
我们推广到三个状态:
我们枚举每次选几个;
(x, y, z)是已知必输状态;
一次选两堆,如果x和原来相同,那么y''-z'' = y-z,一定是必赢状态,所以一堆确定时,令两堆差值和原来一样,我们就可以把他筛掉;
一次选一堆,这是确定x,y,我们就可以把z''转化为z,我们就只需要看f(x,y)这个状态是否为z;
一次选三堆,同时前去一个数达到(x,y,z),他就必赢,要求就是三个数之间的相差值同;
我们从小往大枚举,不断筛数,没有被筛掉的他就必败,这样复杂度N^3
#include<bits/stdc++.h> using namespace std; bool dp[305][305][305], mp[305][305][3]; int a[4]; void init(){ for(int i = 0; i <= 300; i++) for(int j = 0; j <= i; j++) for(int k = 0; k <= j; k++){ bool ok = 1; if(mp[i][j-k][0])ok=0; if(mp[j][i-k][0])ok=0; if(mp[k][i-j][0])ok=0; if(mp[i][j][1])ok=0; if(mp[i][k][1])ok=0; if(mp[j][k][1])ok=0; if(mp[i-j][j-k][2])ok=0; if(ok){ dp[i][j][k]=1; mp[i][j-k][0] = mp[j][i-k][0] = mp[k][i-j][0] = mp[i][j][1] = mp[i][k][1] = mp[j][k][1] = mp[i-j][j-k][2] = 1; } } } int main(){ freopen("stone.in","r",stdin); freopen("stone.out","w",stdout); int T; scanf("%d", &T); init(); while(T--){ int x, y, z; scanf("%d%d%d", &a[0], &a[1], &a[2]); sort(a, a+3); if(dp[a[2]][a[1]][a[0]])puts("No"); else puts("Yes"); } }
第三题:神奇的DP定义;
以上可以2,0,-2序列可以自己手动画画证明;
第一个优化:除了两端中间都可以随便取;
我们已经证明了中间的系数是+2,-2,0,且两个2之间有一个-2,我们如果加上一段数,他大于0就往2中何必,小于0就往-2中合并,或者合并到0中,对答案只增不减;
dp[i][j][k]表示处理到第i个数,分成了j段,处于k阶段
阶段定义:0:处于系数为2
1:处于2后面的0
2:处于系数为-2
3:处于-2后的0
对于,我们可以和前面一起dp[i-1][j][0],可以自成一段,dp[i-1][j-1][3/2],就这样转移好了;
对于两端的系数特殊变成1、-1,中间枚举转移;
初值dp[i][0][1/3] = 0, 其余为-inf,表示开头可以随便从一个地方开始;
答案在dp[i ( i > K) ][K] [0 / 2] 中取max,表示我可以在任意地方结束;
#include<bits/stdc++.h> using namespace std; const int M = 4*1e4 + 5; int read(){ int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*=f; } int dp[M][205][4], a[M]; int main(){ freopen("optimization.in","r",stdin); freopen("optimization.out","w",stdout); int n, k; scanf("%d%d", &n, &k); for(int i = 0; i <= n; i++) for(int j = 0; j <= k; j++) for(int z = 0; z < 4; z++) dp[i][j][z] = -1e9; for(int i = 0; i <= n; i++) dp[i][0][1] = dp[i][0][3] = 0; for(int i = 1; i <= n; i++){ a[i] = read(); for(int j = 1; j <= k; j++){ int xs = 2 - (j == 1 || j == k); dp[i][j][0] = max(dp[i-1][j][0], max(dp[i-1][j-1][3], dp[i-1][j-1][2])) + xs * a[i]; dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0]); dp[i][j][2] = max(dp[i-1][j][2], max(dp[i-1][j-1][0], dp[i-1][j-1][1])) - xs * a[i]; dp[i][j][3] = max(dp[i-1][j][3], dp[i-1][j-1][2]); if(j != 1){ dp[i][j][1] = max(dp[i-1][j-1][1], dp[i][j][1]); dp[i][j][3] = max(dp[i-1][j-1][3], dp[i][j][3]); } } } int ans = -1e9; for(int i = 1; i <= n; i++) for(int j = 1; j <= k; j++) ans = max(dp[i][k][0], max(dp[i][k][2], ans)); printf("%d ", ans); }