3月div场切片记录
CF1007 div2 F数据结构 *2700
CF1008 div2 C构造
CF1008 D dp *1700
void solve(){
cin>>n;
int a=1,b=1,x,y;
int add=0;
char xx,yy;
for(int i=1;i<=n;i++){
cin>>xx>>x>>yy>>y;
if(xx=='+'&&yy=='+'){
add+=x+y;
}
else if(xx=='+'&&yy=='x'){
b+=add;
add=b*(y-1);
add+=x;
}
else if(xx=='x'&&yy=='+'){
a+=add;
add=a*(x-1);
add+=y;
}
else{
int old=add;
if(y>x){
add=(x-1)*a+(y-1)*(b+add);
b+=old;
}
else if(x==y){//注意 相等可以等之后再分配
add+=(x-1)*a+(y-1)*(b+add);
}
else{
add=(x-1)*(a+add)+(y-1)*b;
a+=old;
}
}
}
cout<<add+a+b<<endl;
}
CF1493D DS *1800
题意:n=v=2e5,q次询问,每次单点乘x,全局查gcd,考虑到直接维护会爆long long
因此对每个质数开一个multiset,且每个数质因子个数是<log(v)级别的,因此复杂度2log
void sieve()
{
for (int i = 2; i < N; i++) isprime[i] = 1;
for (int i = 2; i < N; i++){
if (isprime[i]) prime.push_back(i);
for (int &it : prime){
if (1ll * i * it >= N) break;
isprime[i * it] = 0;
if (i % it == 0) break;
}
}
for (int &i : prime)
for(int j=1;j<=N/i;j++)
v[i*j].push_back(i);
}
multiset<int>st[N];
map<int,int>mp;//序列中多少位置出现该质因子
int ans=1;
void solve(){
int q;
cin>>n>>q;
for(int i=1;i<=n;i++) {
cin>>a[i];
int c=a[i];
for(auto j:v[a[i]]){
while(c%j==0) {
c/=j;
if(!st[j].count(i)) mp[j]++;
st[j].insert(i);
if(mp[j]==n){
mp[j]=0;
for(int i=1;i<=n;i++){
st[j].erase(st[j].find(i));
if(st[j].find(i)!=st[j].end()) mp[j]++;
}
ans*=j;
ans%=mod;
}
}
}
}
while(q--){
int p,x;
cin>>p>>x;
int y=x;
for(auto j:v[x]){
while(y%j==0) {
if(!st[j].count(p)) mp[j]++;
y/=j,st[j].insert(p);
if(mp[j]==n){
mp[j]=0;
for(int i=1;i<=n;i++){
st[j].erase(st[j].find(i));
if(st[j].find(i)!=st[j].end()) mp[j]++;
}
ans*=j;
ans%=mod;
}
}
}
cout<<ans<<endl;
}
}
CF1935C 维护最值 *1700
给你n个权值a和b,求最大个数使得$\sum a+max_b-min_b\leq L $$,\ n^2 \leq 4e6$
考虑一个假的反悔贪心,按照b升序排列,在[l,r]中找到最大的sum使得\(sum+b_r-b_l\leq L\)
但这样最后并不一定是减去\(b_l\),可能减去的是一个比\(b_l\)更大的数字,
那么枚举所有区间即可消除影响
CF1919D 思维*2100
定义一种完全二叉树满足任意非叶节点都有2个儿子,且到两个儿子的距离分别为0和1,
给你一个按照dfs序排列叶节点的深度序列,问你是否存在一个满足条件的树
两种思路:
1.逆向考虑,删除节点返回父亲,任取连续两点\(a_i和a_{i+1},|a_i-a_{i+1}|=1\),删除2点
加入\(min(a_i,a_{i+1})\),看最后是否能得到0
因为我们不知道哪些节点是同父亲的两个叶子之一,因此从最大值开始减少,最值点存在相邻元素差为1,那么这个数可以被删除,
实现形式:int->vector,BFS(删完一个数字后相邻数字入队,若该层值未被都访问过那么就不行),两个数组模拟链表
或者如下:
vector<list<int>::iterator> G[200005];
void Solve(){
list<int> a;
cin >> n;
for(int i = 0;i < n;i ++)
G[i].clear();
for(int i = 1,x;i <= n;i ++){
cin >> x;
a.push_back(x);
G[x].push_back(-- a.end());
}
for(int i = n - 1;i;i --){
if(!G[i].size()) continue;
for(auto &it:G[i]){
if(it != a.begin() && *prev(it) == i-1)
a.erase(it),it = a.end();
else if(it != --a.end() && *next(it) == i - 1)
a.erase(it),it = a.end();//it = a.end() 是让 it 不会被访问到
else if(it == -- a.end() || *next(it) != i){
cout << "no\n";
return ;
}
}
for(auto &it:G[i])
if(it != a.end()) //极长连续段中的元素
a.erase(it);
}
if(a.size() > 1 || a.back() != 0)
cout << "no\n";
else cout << "yes\n";
}
2.正向:问题等价于初始序列为0,任取序列中的一个x,将x+1放在x左侧或者右侧(等价于每个x+1左侧或者右侧存在一个x),能否构造得到题目给出序列,然后用单调栈判断,任取一个非0数y,左侧或者右侧必须有小于它的数存在,且等于y-1,每个数都有则满足
上面的做法暂时无法严格证明,但形象感觉上是很对的()
CF2070E 博弈+DS维护 *2200
令c0为区间0个数,c1为1的个数,考虑c0-3*c1胜负的规律
由此统计区间和>=2或者等于-1 树状数组维护即可

浙公网安备 33010602011771号