codeforces global round 1题解搬运

A,B很简单,跳过了。
C题规律相当明显,可以直接对\(2^n-1\)打表,也可以不打表直接算最大因数。
D题两种操作转化一下DP即可。
E题考虑查分数组不变的性质。
F题考虑dfs时动态维护每个叶子的深度,从一个节点走向它的孩子相当于孩子对应的区间加,不包含孩子的区间减。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int P=1050000;
const int N=500010;
int u;
ll st[P],tag[P],tg;
void pushup(int x){
  st[x]=min(st[x<<1],st[x<<1|1])+tag[x];
}
void Add(int s,int t,ll v){
  int ss=u+s,tt=u+t;
  for (s+=u-1,t+=u+1; s^t^1; pushup(ss>>=1),pushup(tt>>=1),s>>=1,t>>=1){
    if (~s&1) st[s^1]+=v,tag[s^1]+=v;
    if (t&1) st[t^1]+=v,tag[t^1]+=v;
  }
  for (s>>=1,t>>=1; s!=t; s>>=1,t>>=1) pushup(s),pushup(t);
  for (; s; s>>=1) pushup(s);
}
ll ask(int s,int t){
  ll retl=LLONG_MAX>>1,retr=retl;
  int ss=u+s,tt=u+t;
  for (s+=u-1,t+=u+1; s^t^1; retl+=tag[ss>>=1],retr+=tag[tt>>=1],s>>=1,t>>=1){
    if (~s&1) retl=min(retl,st[s^1]);
    if (t&1) retr=min(retr,st[t^1]);
  }
  for (s>>=1,t>>=1; s!=t; s>>=1,t>>=1) retl+=tag[s],retr+=tag[t];
  retl=min(retl,retr);
  for (; s; s>>=1) retl+=tag[s];
  return retl;
}
int clk,dfn[N],en[N];
vector<pair<int,int> > g[N];
vector<int> a[N];
ll ans[N];
int la[N],ra[N];
void dfs(int x,ll dep){
  //cerr<<x<<" "<<dep<<endl;
  dfn[x]=++clk;
  if (!g[x].size()){
    st[u+clk]=dep;
    en[x]=clk;
    return;
  }
  st[u+clk]=LLONG_MAX>>1;
  for (auto j:g[x])
    dfs(j.first,dep+j.second);
  en[x]=clk;
}
void dfs2(int x){
  for (auto j:a[x]) ans[j]=tg+ask(la[j],ra[j]);
  for (auto j:g[x]){
    tg+=j.second;
    Add(dfn[j.first],en[j.first],-j.second*2);
    dfs2(j.first);
    Add(dfn[j.first],en[j.first],j.second*2);
    tg-=j.second;
  }
}
int n,q;
int main(){
  scanf("%d%d",&n,&q);
  for (int i=2; i<=n; ++i){
    int x,y;
    scanf("%d%d",&x,&y);
    g[x].push_back(make_pair(i,y));
  }
  for (u=1; u<n; u<<=1);
  --u;
  dfs(1,0);
  //for (int i=u+1; i<=u+n; ++i) cout<<st[i]<<" "; cout<<endl;
  for (int i=u+n+1; i<=u+u+1; ++i) st[i]=LLONG_MAX>>1;
  for (int i=u; i; --i) st[i]=min(st[i<<1],st[i<<1|1]);
  for (int i=1; i<=q; ++i){
    int x;
    scanf("%d%d%d",&x,&la[i],&ra[i]);
    a[x].push_back(i);
  }
  //cerr<<"????"<<endl;
  dfs2(1);
  for (int i=1; i<=q; ++i) cout<<ans[i]<<'\n';
}

这个zkw写得我好恶心,早知道还是写普通线段树了。
G题非常神仙,先考虑构造一个
1------2---------3
|______4
来代替1这个原有的白点。
然后原图就没有染过色的点了。

考虑有度为4的点那么先手必胜。
如果有度为3且第二长的儿子比2长的点,那么先手必胜。
考虑你现在只可能有最多两个度为3的点了。
只有0或1个3度点,那么是和局。
两个的话,必定组成一根“骨头”,分奇偶讨论即可。

#include <bits/stdc++.h>
using namespace std;
vector<vector<int> > G;
vector<bool> vis;
void aDD(int x,int y){
  if (x>=G.size()) G.resize(x+1);
  if (y>=G.size()) G.resize(y+1);
  G[x].push_back(y);
  G[y].push_back(x);
}
bool dfs(int x,int len){
  vis[x]=1;
  if (G[x].size()>=3&&len&&len%2==0) return 1;
  for (auto j:G[x])
    if (!vis[j]&&dfs(j,len+1)) return 1;
  return 0;
}
int n,t;
string s;
int main(){
  ios_base::sync_with_stdio(false); cin.tie(NULL);
  int t; cin>>t;
  while (t--){
    cin>>n;
    G=*(new vector<vector<int> >(2));
    vis.clear();
    for (int i=1; i<n; ++i){
      int u,v;
      cin>>u>>v;
      aDD(u,v);
    }
    int cnt=n;
    cin>>s;
    for (int i=1; i<=n; ++i)
      if (s[i-1]=='W'){
    aDD(i,cnt+1);
    aDD(cnt+1,cnt+2);
    aDD(cnt+1,cnt+3);
    cnt+=3;
      }
    vis.resize(cnt+1);
    for (int i=1; i<=cnt; ++i) if (G[i].size()>=4) goto l1;
    for (int i=1; i<=cnt; ++i)
      if (G[i].size()>=3){
      vector<int> v;
      for (auto j:G[i])
    v.push_back(G[j].size());
      sort(v.rbegin(),v.rend());
      if (v[1]>=2) goto l1;
    }
    for (int i=1; i<=cnt; ++i)
      if (G[i].size()>=3&&dfs(i,0)) goto l1;
    puts("Draw");
    continue;
    l1:puts("White");
  }
}

H题虽然不那么神仙,但是代码难度爆炸,错了也不知道怎么调QAQ
首先每个符合区间限制的数肯定一一对应正则表达式的个数。
于是你只需要统计正则表达式的个数就可以了。
将正则表达式映射到AC自动机上,
DP时在AC自动机上走就行了,同时询问一下该节点剩余长度匹配的正则表达式个数。
并不需要关心后面具体填了什么,因为只要长度够,就符合正则表达式。
一堆细节,十分恶心。

#include <bits/stdc++.h>
using namespace std;
const int N=2005;
const int M=805;
const int NODE=M*20;
const int INF=~0u>>1;
int trans[NODE][10],fail[NODE],tot;
int val[NODE][M];
int f[N][NODE];
bool way[N][NODE];
string l,r;
int n,m;
void depth(int now,int p,bool dlim,bool ulim){
    if (now>=m){
        //cerr<<"ADD"<<p<<" "<<0<<endl;
        ++val[p][0];
        return;
    }
    if (!dlim&&!ulim){
        //cerr<<"ADD"<<p<<" "<<m-now<<endl;
        ++val[p][m-now];
        return;
    }
    //cerr<<now<<" "<<l.size()<<" "<<r.size()<<endl;
    int llim=(dlim?l[now]-'0':0);
    int rlim=(ulim?r[now]-'0':9);
    //cerr<<"????"<<llim<<" "<<rlim<<endl;
    for (int i=max(llim,(int)!now); i<=rlim; ++i){
        //cerr<<"I"<<p<<" "<<i<<endl;
        int to=(trans[p][i]?trans[p][i]:trans[p][i]=++tot);
        //cerr<<"dfs"<<p<<" "<<i<<" "<<to<<endl;
        depth(now+1,to,dlim&&i==llim,ulim&&i==rlim);
        //cerr<<"ED"<<endl;
    }
}
void build_fail(){
    /*for (int i=0; i<=tot; ++i)
        for (int j=0; j<=m; ++j)
        cerr<<i<<" "<<j<<" "<<val[i][j]<<endl;*/
    //cerr<<val[8][2]<<endl;
    queue<int> q; q.push(0);
    while (!q.empty()){
        int x=q.front(); q.pop();
        //cerr<<x<<" ";
        for (int i=0; i<=9; ++i){
            int v=trans[x][i];
            //cerr<<"BBBBBB"<<x<<" "<<i<<" "<<fail[x]<<" "<<v<<endl;
            if (v){
                q.push(v);
                if (x){
                    fail[v]=trans[fail[x]][i];
                }
                for (int i=0; i<=m; ++i)
                        val[v][i]+=val[fail[v]][i];
            }
            else trans[x][i]=trans[fail[x]][i];
        }
    }
    for (int i=0; i<=tot; ++i){
        for (int j=1; j<=m; ++j)
            val[i][j]+=val[i][j-1];
        //cerr<<fail[i]<<endl;
        //for (int j=0; j<=m; ++j)
            //cout<<i<<" "<<j<<" "<<val[i][j]<<endl;
    }
}
int main(){
    //fprintf(stderr,"cfh.in");
    ios::sync_with_stdio(0);
    cin>>l>>r>>n;
    /*for (int i=1; i<=800; ++i) l+="1";
    for (int i=1; i<=800; ++i) r+="2";
    n=2000;*/
    if (l.size()==r.size()){
        m=r.size();
        depth(0,0,1,1);
    }
    else{
        int p=m=l.size();
        depth(0,0,1,0);
        //cerr<<"END"<<endl;
        m=r.size();
        while (l.size()<m) l="0"+l;
        depth(0,0,0,1);
        for (int i=p+1; i<m; ++i) ++val[0][i];
    }
    //return 0;
    build_fail();
    //cerr<<"!!!"<<endl;
//return 0;
    //return 0;
    /*for (int i=0; i<=tot; ++i){
        cerr<<"I----"<<i<<endl;
        cerr<<"fail"<<fail[i]<<endl;
        for (int j=0; j<=9; ++j) cerr<<trans[i][j]<<" ";
        cerr<<endl;
        }*/
    //return 0;
    for (int i=0; i<=n; ++i)
        for (int j=0; j<=tot; ++j)
            f[i][j]=-INF;
    f[0][0]=val[0][min(n,m)];

    for (int i=0; i<n; ++i){
        for (int j=0; j<=tot; ++j){
            for (int k=0; k<=9; ++k){
                int v=trans[j][k];
                f[i+1][v]=max(f[i+1][v],f[i][j]+val[v][min(n-i-1,m)]);
                //cerr<<"dp"<<i+1<<" "<<v<<" "<<f[i+1][v]<<" "<<f[0][0]<<" "<<val[v][min(n-i-1,m)]<<" "<<j<<endl;
            }
        }
    }
    int ans=0;
    for (int i=0; i<=tot; ++i) ans=max(ans,f[n][i]);
    cout<<ans<<'\n';
    for (int i=0; i<=tot; ++i) way[n][i]=(f[n][i]==ans);
    for (int i=n-1; i>=0; --i)
        for (int j=0; j<=tot; ++j){
            for (int k=0; k<=9; ++k){
                int v=trans[j][k];
                if (way[i+1][v]&&f[i+1][v]==f[i][j]+val[v][min(n-i-1,m)]){
                    way[i][j]=1;
                    break;
                }
            }
        }
    int now=0,len=0;
    while (len<n){
        for (int k=0; k<=9; ++k){
            int v=trans[now][k];
            if (way[len+1][v]&&f[len+1][v]==f[len][now]+val[v][min(n-len-1,m)]){
                now=v;
                cout<<k;
                break;
            }
        }
        ++len;
    }
}

原文地址:https://www.cnblogs.com/Yuhuger/p/10420898.html

时间: 2024-10-28 13:15:19

codeforces global round 1题解搬运的相关文章

Codeforces Global Round 3 题解

A 送分题 B 送分题 C 考虑先依次把\(2\sim n-1\)换到正确的位置,这个只要利用\(1,n\)两个位置交换就行了. 然后如果\(n\)在第一位就交换\(1,n\). D 显然\(a<b\)和\(a>b\)的可以分别考虑.不失一般性考虑\(a<b\)的.那么相当于要选出若干二元组并排序,要求满足\(b_i>a_{i+1}\).考虑对数值建点,\(a\)向\(b\)连边,所有\(i\)向\(i-1\)连边,相当于要走一条路径经过最多\(a->b\)的边.这样可以直观

Codeforces Global Round 4 题解

技不如人,肝败吓疯…… 开场差点被 A 题意杀了,幸好仔细再仔细看,终于在第 7 分钟过掉了. 跟榜.wtf 怎么一群人跳题/倒序开题? 立刻紧张,把 BC 迅速切掉,翻到了 100+. 开 D.感觉有点吓人……感觉有点可做? 的确挺可做.再切掉 D,但是此时已经到 300+ 了. 没事,还能翻. 开 E.这……什么玩意? 瞄了一眼 F1,…… 盯着这两题盯到自闭. 最后 rk 1000 左右.我的名字颜色真的是对的吗…… A 看懂题了就是水题.选上所有小于等于第一个党派一半人数的党派,如果不行

Codeforces Global Round 7 题解

A 一种合法构造方式是\(299\cdots 9\) code B 发现每次的\(x_{i-1}\)都是知道的,于是可以直接递推. code C 最终答案所选的数一定是\(n-k+1\)到\(n\)的所有数.把这些数所在的位置记作\(p_1,p_2,\cdots,p_k\). 不难发现每个\(r_i\in [p_i,p_{i+1})\),于是答案就是\(\prod (p_{i+1}-p_i)\). code D 首先把首尾能构成回文的部分删掉,因为这部分一定会出现在答案中. 问题变成了在当前字符

Codeforces Global Round 1 (A-E题解)

Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^(k-1)+a2*b^(k-2)+...+ak*b^0的奇偶性. 题解: 暴力求模2意义下的值就好了. 代码如下: #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; int

【手抖康复训练1 】Codeforces Global Round 6

[手抖康复训练1 ]Codeforces Global Round 6 总结:不想复习随意打的一场,比赛开始就是熟悉的N分钟进不去时间,2333,太久没写题的后果就是:A 题手抖过不了样例 B题秒出思路手抖过不了样例,C题秒出思路手抖过不了样例*3 D题 手抖 过的了样例 ,调了1h,赛后发现变量名写错了,改一个字符就能AC... 题目等补完题一起放上来QAQ 原文地址:https://www.cnblogs.com/ttttttttrx/p/12110199.html

Codeforces Global Round 7【ABCD】(题解)

目录 涵盖知识点:思维.构造.马拉车. 比赛链接:传送门 D题只有数据范围的区别,故只写D2. 好多题啊,随缘更新.(其实懒得写) A - Bad Ugly Numbers B - Maximums C - Permutation Partitions D2 - Prefix-Suffix Palindrome (Hard version) 涵盖知识点:思维.构造.马拉车. 比赛链接:传送门 D题只有数据范围的区别,故只写D2. 好多题啊,随缘更新.(其实懒得写) A - Bad Ugly Nu

Codeforces Global Round 5 部分题解

tourist的劲题,掉了17分,着实心痛,本来是有分可恰到的 A.给你一个数列\(a\),你需要构造一个数列\(b\),使得每一个\(b\)都等于\(a/2\),向上或向下取整由你决定 并且还要使得\(\sigma b\)的总和等于0 数据是保证有解的 那么我们就令所有\(b\)等于\(\lfloor a/2 \rfloor\),求出总和 再遍历一遍数组,sum过大则把某些负数调整为向上取整,否则把正数调整 代码: #include <bits/stdc++.h> #define int l

【 Codeforces Global Round 1 B】Tape

[链接] 我是链接,点我呀:) [题意] x轴上有m个连续的点,从1标号到m. 其中有n个点是特殊点. 让你用k段区间将这n个点覆盖. 要求区间的总长度最小. [题解] 一开始假设我们需要n个胶带(即包含每一个点) 然后因为k<=n 所以可能胶带不够用. 那么就得一个胶带跨过两个点. 怎么选择最好呢? 可以把b[i]-b[i-1]-1处理出来排个序. (优先取较小的花费) 然后取前n-k个累加和sum. 因为每取一个就少用一段胶带. 然后sum+n就是答案了 [代码] import java.i

【Codeforces Global Round 1 C】Meaningless Operations

[链接] 我是链接,点我呀:) [题意] 给你一个a 让你从1..a-1的范围中选择一个b 使得gcd(a^b,a&b)的值最大 [题解] 显然如果a的二进制中有0的话. 那么我们就让选择的b的二进制中对应的位置为1 剩下全为0就好 这样a的二进制全都变成1之后就是答案了(gcd的右边是0). 但是如果a的二进制里面全是1的话. 就没办法这么构造了 这里有两种情况. ①.1的个数是偶数 那么就101010这样构造 另外一个数就是010101 答案就是010101转换成十进制 ②.1的个数是奇数