中秋节yyds
P8539 「Wdoi-2」来自地上的支援
为什么都在用线段树啊?
首先,我们发现一个数如果有一次没有被选,那它以后就永远不会被选上了,所以x被选k次的临界是它从x到x+k-1一直被选上,x+k-1>n就不合法了。
为了保证这个数在它自己的位置上被选中第一次,它需要比前面的修改后最大值大或相等(因为修改值和原值相等时选原值),继续修改下去,它自己的不断增加的修改值还要大于后面的每一个原值。
这里涉及到了修改值的预处理,先用没有任何变动的A进行题目中的操作,因为比较的只是相对大小,与其每次找出来最大的让它+v,不如先对于每一个数把v*i减掉,比较相对大小时就相当于和与它比较的数的修改值相比了。
所以就用线段树——前面的预处理,后面的最大值区间查询。
可是线段树是没有必要的。
我们发现要保持在1~x-1和x+1~x+k-1之内只要区间够大就要必选x,所以我们只需要一个前缀,f[i]表示在原来的A中截止到i最大的修改值的位置,就是他原来由于B最大什么的已经加上了若干个v,我们只需要让A比这个临界区间范围内最大可能的B大就好了。
分成4种情况:
前两种,如果这最大值就是x,那么它是无效的,因为x的初始值成了变量,它原来在A中的值是可行解但不是最优解,所以预处理的时候还要处理上次大值g,不用严格(可以相等),把这个g看做是最大值,如果它出现在x之前,修改值和它相等就可以了,出现在x之后就需要修改值一定比它大。x需要加上它和最大值的差值,如果最大值在它之前就加上正差距,否则加上负差距,在代码里的体现是x*v和A[maxpos]直接加,因为A都是减过的。
最大值不是x那直接用最大值f就可以了,不管次大值g什么事,其他的都一样。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const int INF = 0x7fffffff; int n, m, X[maxn], K[maxn]; ll v, A[maxn], f[maxn], g[maxn], w, l; ll an2, an1; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); m = read(); v = read(); for(int i=1; i<=n; i++) { A[i] = read(); } for(int i=1; i<=m; i++) { X[i] = read(); K[i] = read(); } A[0] = -INF; for(int i=1; i<=n; i++) { A[i] = w = A[i] - i*v; if(w >= A[f[i-1]]) g[i] = f[i-1], f[i] = i; else if(w >= A[g[i-1]]) g[i] = i, f[i] = f[i-1]; else g[i] = g[i-1], f[i] = f[i-1]; } for(int i=1; i<=m; i++) { int x = X[i], k = K[i], y = x+k-1; l = 0; if(y < n) l = max(0ll, x*v+(f[y]==x?A[g[y]]+(g[y]>x):A[f[y]]+(f[y]>x))); an1 ^= l; an2 += l; } printf("%lld %lld\n", an1, an2); return 0; }
P8540 「Wdoi-2」夜空中的 UFO 恋曲
众所周知,猫的天性是比较懒的……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const ll mod = 1e17; ll a, b, c; inline ll read() { ll x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } ll lowbit(ll x) { return x & -x; } int main() { a = read(); b = read(); c = read(); if(c & 1) { if(a & 1) { if(b & 1) printf("%lld\n", lowbit((c*c)^c)); //== qpow(c, c)*qpow(c, c)^c取lowbit结果可以溢出用unsigned,但是指数不能溢出 //第一次操作后a末位是1,^c变成了0,qpow 2c 就出现了2*c个后缀0^c就等效成了c //因为a,b,c>1,后面的奇数次运算就可以把a等效成c else printf("1\n"); } else { if(b & 1) printf("1\n"); else printf("%lld\n", lowbit((c*c)^c)); } } else { if(a & 1) printf("1\n"); else printf("%lld\n", lowbit(c)); } return 0; }
时光花火,水月星辰