CF835

CF835

CF835A

链接

CF835A题意

两个人参加打字比赛,已知一共有 s s s 个字符,两人的网络延迟分别是 t 1 , t 2 t_1,t_2 t1,t2,打每个字符的速度分别是 v 1 , v 2 v_1,v_2 v1,v2,一场比赛的用时是下载用时+打字用时+上传用时,请问谁的总用时最小

CF835A题解

总用时 T i = 2 × t i + s × v i T_i=2\times t_i+s\times v_i Ti=2×ti+s×vi,比一下就好了

CF835A代码

#include<bits/stdc++.h>
using namespace std;
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 s, v1, v2, t1,t2;
signed main(){
    s = read(); v1 = read(); v2 = read(); t1 = read(); t2 = read();
    if(2 * t1 + s * v1 < 2 * t2 + s * v2){puts("First");}
    if(2 * t1 + s * v1 == 2 * t2 + s * v2){puts("Friendship");}
    if(2 * t1 + s * v1 > 2 * t2 + s * v2){puts("Second");}
    return 0;
}

CF835B

链接

CF835B题意

给两个数 k , n k,n k,n,要改变 n n n 的尽量少的位数,使得 n n n 的每一位值之和不小于 k k k

CF835B题解

贪心的想,每一次把 n n n 中最小的位置换成 9 9 9,这样改变的位数最少

CF835B代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int k, sum;char ch[maxn];
priority_queue<int,vector<int>, greater<int> > que;
signed main(){
    scanf("%d",&k); scanf("%s",ch + 1);int len = strlen(ch + 1);
    for(int i = 1;i <= len;i++){que.push(ch[i] - '0');sum += int(ch[i] - '0');}
    int cnt = 0;
    // printf("%d\n",que.top());
    while(sum < k && !que.empty()){sum += (9 - que.top());que.pop();cnt++;}
    printf("%d\n",cnt);
    return 0;
}

CF835C

链接

CF835C题意

在一个笛卡尔系中有 n ( n ≤ 1 0 5 ) n(n \le 10^5) nn105 个星星,最大亮度是 C ( C ≤ 10 ) C(C \le 10) CC10,第 i i i 个星星的坐标是 ( x i , y i ) (x_i,y_i) xi,yi, 亮度是 s i s_i si
但是这些星星的亮度会随时间变化,具体而言,设 t t t 时刻第 i i i 个星星的亮度为 f i ( t ) f_i(t) fi(t),那么 f i ( t ) = ( s i + t )   m o d   C f_i(t)=(s_i+t) \space mod \space C fi(t)=(si+t) mod C
现在给出 q q q 个询问,第 i i i 次询问,以 ( x i 1 , y i 1 ) (x_{i1},y_{i1}) (xi1,yi1) 为左上角, ( x i 2 , y i 2 ) (x_{i2},y_{i2}) (xi2,yi2) 为右下角的矩阵中,在 t i t_i ti 时刻的亮度之和

CF835C题解

如果设 ( i , j ) (i,j) (i,j) 位置的星星有 k k k 个(为 c 1 , 2 , . . . , k c_{1,2,...,k} c1,2,...,k),那么在时间 T T T 的时候答案就是 a n s i , j , T = ∑ i = 1 k ( ( s i + t )   m o d   C ) ans_{i,j,T}=\sum_{i=1}^k((s_i+t) \space mod \space C) ansi,j,T=i=1k((si+t) mod C)
不难发现最外面没有 m o d   C mod\space C mod C,不能简单 m o d mod mod
发现 C C C 很小,而且时间每经过一个 C C C 周期答案就会循环一次,于是想到直接预处理 m o d   C = k mod\space C=k mod C=k 时的答案
然后就没有然后了

CF835C代码

#include<bits/stdc++.h>
using namespace std;
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;
}
const int maxn = 110, maxm = 1e5 + 10;
int cf[maxn][maxn][11];
int x[maxm], y[maxm], col[maxm];
int n, q, C;
signed main(){
    n = read(); q = read(); C = read() + 1;
    for(int i = 1;i <= n;i++){
        x[i] = read(); y[i] = read(); col[i] = read();
        for(int j = 0;j < C;j++){cf[x[i]][y[i]][j] += ((col[i] + j) % C);}
    }
    for(int k = 0;k < C;k++)
        for(int i = 1;i <= 100;i++)
            for(int j = 1;j <= 100;j++)
                cf[i][j][k] = (cf[i][j][k] + cf[i - 1][j][k] + cf[i][j - 1][k] - cf[i - 1][j - 1][k]);
    int t, xl, xr, yl, yr;
    for(int i = 1;i <= q;i++){
        t = read() % C; xl = read() - 1; yl = read() - 1; xr = read(); yr = read();
        printf("%d\n",cf[xr][yr][t] - cf[xr][yl][t] - cf[xl][yr][t] + cf[xl][yl][t]);
    }
    return 0;
}

CF835D

链接

CF835D题意

给出一个字符串 S S S ∣ S ∣ ≤ 5000 |S|\le 5000 S5000),同时定义一个子串的等级
f ( l , r ) = { 0    ( ( l , r ) 不是回文串 ) f ( l , m i d ) + 1    ( ( l , r ) 是回文串, ( l , m i d ) 是 ( l , r ) 的左半子串 ) f(l,r)={\begin{cases} 0\,\,((l,r)不是回文串)\\ f(l,mid)+1\,\,((l,r)是回文串,(l,mid)是(l,r)的左半子串)\\ \end{cases}} f(l,r)={0((l,r)不是回文串)f(l,mid)+1((l,r)是回文串,(l,mid)(l,r)的左半子串)

CF835D题解

一个很显然的思路,类似区间DP的思想,暴力枚举子串(顺序为长度从小到大),判断这个子串的左半子串是不是回文串,然后加一下就好了
判断的话可以直接Hash

CF835D代码

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
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;
}
const int maxn = 5e3 + 10;
const ull  K = 27;
ull hashh[maxn][2], up[maxn];
char ch[maxn];
int n;
int pos[maxn][maxn];
ll ans[maxn];
ull Hash(int l,int r,int opt){
    if(opt)return (hashh[l][opt] - hashh[r + 1][opt] * up[r - l + 1]);
    return (hashh[r][opt] - hashh[l - 1][opt] * up[r - l + 1]);
}
signed main(){
    scanf("%s",ch + 1);n = strlen(ch + 1);
    up[0] = 1;
    for(int i = 1;i <= n;i++){
        hashh[i][0] = (hashh[i - 1][0] * K + (ull)(ch[i] - 'a'));
        up[i] = up[i - 1] * K;
    }
    for(int i = n;i;i--){hashh[i][1] = (hashh[i + 1][1] * K + (ull)(ch[i] - 'a'));}
    for(int i = 1;i <= n;i++)pos[i][i] = 1;
    for(int len = 2;len <= n;len++){
        for(int i = 1;i + len - 1 <= n;i++){
            int j = i + len - 1,k,l;
            if(len & 1){k = i + len / 2 - 1;l = i + (len + 1) / 2;}
            else {k = i + len / 2 - 1;l = i + len / 2;}
            if(Hash(i,k,0) == Hash(l,j,1) && Hash(i,k,1) == Hash(l,j,0)){
                pos[i][j] = max(pos[i][j],pos[i][k] + 1);
            }
        }
    }
    for(int len = 1;len <= n;len++){
        for(int i = 1;i + len - 1 <= n;i++){
            int j = i + len - 1, k = i + (len + 1) / 2 - 1,l = i + len - len / 2;
            ans[pos[i][j]]++;
            // printf("pos[%d][%d]=%d\n",i,j,pos[i][j]);
        }
    }
    // printf("hash(1,2)=%llu,hash(3,4)=%llu\n",Hash(1,2,0),Hash(3,4,1));
    for(int i = n;i;i--)ans[i] += ans[i + 1];
    for(int i = 1;i <= n;i++)printf("%lld ",ans[i]);
    return 0;
}

CF835E

链接

CF835E题意

这是一道交互题
有一个长度为 n n n 的数组 a 1 , 2 , . . . , n a_{1,2,...,n} a1,2,...,n, 其中只有两个数字是 y y y,剩下的都是 x x x
每次你都可以给出一个下标集合 S S S,交互库会回答 a S 1   x o r   a S 2   x o r   . . .   x o r   a S k a_{S_1} \space xor \space a_{S_2} \space xor \space ... \space xor \space a_{S_k} aS1 xor aS2 xor ... xor aSk 的答案并返回给你
最多问交互库 19 19 19 次问题
你需要回答出数字是 y y y 的数字在数组中的下标

CF835E题解

首先可以画出以下表格

S . s i z e ( ) S.size() S.size()含有 y y y 的数量交互库的答案
奇数奇数 y y y
奇数偶数 x x x
偶数奇数 x   x o r   y x\space xor\space y x xor y
偶数偶数 0 0 0

然后按照二进制分集合,询问交互库答案
可以得到答案编号的 x o r xor xor值(设为 t m p tmp tmp,第 i i i 位如果含有 y y y 的数量是奇数则为 1 1 1,否则为 0 0 0
同时可以得到一个只含有一个 y y y 的集合 S 1 S_1 S1
通过二分集合 S 1 S_1 S1 可以得出一个答案编号(设为 a n s 1 ans_1 ans1
因为 a n s 1   x o r   a n s 2 = t m p ans_1 \space xor \space ans_2 = tmp ans1 xor ans2=tmp
所以 a n s 2 = t m p   x o r   a n s 1 ans_2 = tmp \space xor \space ans_1 ans2=tmp xor ans1
最后别忘了把答案排下序
然后就没有然后了

CF835E代码

#include<bits/stdc++.h>
using namespace std;
int n, x, y, tmp;
vector<int> vec1,vec;
void solve(int l,int r){
    if(l == r){
        cout << "! " << min(vec1[l],(tmp ^ vec1[l])) << ' ' << max((tmp ^ vec1[l]),vec1[l])<< endl;
        exit(0);
    }
    int mid = l + r >> 1;vec.clear();
    for(int i = l;i <= mid;i++){vec.push_back(vec1[i]);}
    cout << "? " << vec.size();for(int i : vec)cout << ' ' << i;cout << endl;
    int res;cin >> res;
    if(vec.size() % 2){
        if(res == y){solve(l,mid);}
        else solve(mid + 1,r);
    }
    else{
        if(res == (x ^ y)){solve(l,mid);}
        else solve(mid + 1,r);
    }
}
signed main(){
    cin >> n >> x >> y;
    for(int i = 9;i + 1;i--){
        vec.clear();
        for(int j = 1;j <= n;j++){if(j & (1 << i))vec.push_back(j);}
        if(!vec.size())continue;
        cout << "? " << vec.size();for(int j : vec){cout << ' ' << j;}cout << endl;
        int res;cin >> res;
        if(vec.size() % 2){
            if(res == y){
                if(!vec1.size()){for(int j : vec)vec1.push_back(j);}
                tmp |= (1 << i);
            }
        }
        else{
            if(res == (x ^ y)){
                if(!vec1.size()){for(int j : vec)vec1.push_back(j);}
                tmp |= (1 << i);
            }
        }
    }
    solve(0,vec1.size() - 1);
    return 0;
}

CF835F

链接

CF835F题意

给出一个有 n ( n ≤ 2 × 1 0 5 ) n(n \le 2 \times 10^5) nn2×105 个节点的基环树(有 n n n 条边),每条边有一个权值 w i w_i wi,现在需要删除一条边使得

  • 所有节点仍联通
  • 删去这条边后所得的树的直径尽可能小

现在需要求出这个最小值

CF835F题解

这个shaber题调了我半个月
细节超多,我们从头说起
首先找到这个环,如果断开这个环上所有边的话,各个在环上的顶点就变成了一个一个的什么啊的子树的根。
容易发现这些子树的边是不能断开的,于是先用树形DP求一下各个子树的直径(记其最大值为 a n s 1 ans1 ans1),并求出每个顶点到自己子树中最长链的值 v a l i val_i vali
然后尝试求断开这个拥有 k k k 个节点的环上一条边之后的直径最小值(记为 a n s 2 ans2 ans2)。
首先先按顺时针(逆时针也行)将环铺开,记录第 i i i 个节点的权值 v a l i val_i vali 和通向下一个节点的边权 w e i i wei_i weii (特别的, w e i k wei_k weik k k k 通向 1 1 1 的边权)。
然后考虑如果断开 i , i + 1 i,i+1 i,i+1 这条边之后,直径的取值可能是什么。
直径可能是 [ 1 , i ] [1,i] [1,i] [ i + 1 , k ] [i+1,k] [i+1,k] 中的某一条路径成为直径,或者是通过 n , 1 n,1 n,1(也就是将一段 [ x , k ] [x,k] [x,k] 和另一段 [ 1 , y ] [1,y] [1,y] 拼在一起)的某一条路径成为路径。
这三种都是可以维护的,然后枚举一下删哪条边就好了(删除 [ k , 1 ] [k,1] [k,1] 这条边需要特判一下)

CF835F注意事项

  1. 树的直径如果用DP求的话,直径是所有点 i i i max ⁡ ( d p i , 0 + d p i , 1 ) \max(dp_{i,0}+dp_{i,1}) max(dpi,0+dpi,1) 而不是只有根节点可以统计
  2. 特判 [ n , 1 ] [n,1] [n,1] 这条边的时候需要将 a n s 2 ← 0 ans2 \gets 0 ans20 然后再统计,别赋值成 I N F INF INF 然后这种就统计不到了
  3. 这道题确实是一道基环树的好题,还有双倍经验(将这道题的答案除以 2.0 2.0 2.0 就是双倍经验的答案了)

CF835F代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
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;
}
const int maxn = 3e5 + 10;
int n;
int head[maxn], tot = 1;
struct edge{
    int from, to, nexte, wei;
    edge(int fr = 0,int to = 0,int ne = 0,int we = 0):from(fr),to(to),nexte(ne),wei(we){}
}e[maxn << 1];
void add(int u,int v,int w){e[++tot] = edge(u,v,head[u],w);head[u] = tot;}

bool book[maxn];
int fat[maxn];
bool ring[maxn];
bool dfs1(int u,int father){
// printf("u = %d\n",u);
    book[u] = 1;
    for(int i = head[u];i;i = e[i].nexte){
        int v = e[i].to;if(v == fat[u])continue;
        fat[v] = u;
        if(!book[v]){if(dfs1(v,u))return 1;}
        else{
            int tmp = u;
            while(1){
// printf("top() = %d\n",tmp);
                ring[tmp] = 1;tmp = fat[tmp];
                if(tmp == u)break;
            }
            return 1;
        }
    }
    return 0;
}

int f[maxn][2];
void dfs2(int u,int father){
    for(int i = head[u];i;i = e[i].nexte){
        int v = e[i].to, w = e[i].wei;
        if(v == father || ring[v])continue;
        dfs2(v, u);
        if(f[v][0] + w > f[u][0]){f[u][1] = f[u][0];f[u][0] = f[v][0] + w;}
        else if(f[v][0] + w > f[u][1]){f[u][1] = f[v][0] + w;}
    }
}

int wei[maxn], val[maxn];
int idx, mp[maxn];
void dfs3(int u,int father){
    if(book[u]){return;}book[u] = 1;
    idx++; val[idx] = f[u][0];mp[u] = idx;
    for(int i = head[u];i;i = e[i].nexte){
        int v = e[i].to, w = e[i].wei;
        if(!ring[v] || v == father)continue;
        wei[idx] = w;dfs3(v, u);break;
    }
}

int suf[maxn], pre[maxn];
int pre1[maxn], suf1[maxn];

signed main(){
// #ifndef ONLINE_JUDGE
//     freopen("P1399_4.in","r",stdin);
// #endif
    n = read();int u, v, w;
    for(int i = 1;i <= n;i++){
        u = read(); v = read(); w = read();
        add(u, v, w);add(v, u, w);
    }
    
    /*找基环*/ dfs1(1, 1);
// puts("11111");
    /*算各自子树最大值,并统计各自子树直径*/
    int ans2 = 0;
    for(int i = 1;i <= n;i++)
        if(ring[i]){dfs2(i,i);}
    for(int i = 1;i <= n;++i)ans2 = max(ans2,f[i][0] + f[i][1]);
// puts("22222");
// for(int i = 1;i <= n;i++)printf("ring[%d]=%d\n",i,ring[i]);
    /*将环转变成链并重新编号*/
    memset(book,0,sizeof(book));
    for(int i = 1;i <= n;i++){if(ring[i]){dfs3(i,i);break;}}

// for(int i = 1;i <= n;i++){printf("mp[%d] = %d\n",i,mp[i]);}
    /*统计答案*/
    pre[1] = val[1];int tmp = 0;
    for(int i = 2;i <= idx;i++){
        tmp += wei[i - 1];
        pre[i] = max(pre[i - 1],val[i] + tmp);
    }
    suf[idx] = val[idx];tmp = 0;
    for(int i = idx - 1;i;i--){
        tmp += wei[i];
        suf[i] = max(suf[i + 1], val[i] + tmp);
    }
// for(int i = 1;i <= idx;i++)printf("pre[%d] = %d\n",i,pre[i]);
// for(int i = 1;i <= idx;i++)printf("suf[%d] = %d\n",i,suf[i]);
    int ans1 = 0, prex = val[1]; pre1[1] = val[1];
    for(int i = 1;i < idx;i++){
        pre1[i + 1] = prex + wei[i] + val[i + 1];
        prex += wei[i];prex = max(prex,val[i + 1]);
    }
    for(int i = 2;i <= idx;i++){pre1[i] = max(pre1[i],pre1[i - 1]);}
    int sufx = val[idx]; suf1[idx] = val[idx];
    for(int i = idx;i > 1;i--){
        suf1[i - 1] = sufx + wei[i - 1] + val[i - 1];
        sufx += wei[i - 1];sufx = max(sufx,val[i - 1]);
    }
    for(int i = idx - 1;i;i--)suf1[i] = max(suf1[i],suf1[i + 1]);
    for(int i = 1;i <= idx;i++){ans1 = max(ans1,pre1[i]);}
// printf("%lld~%lld : %lld\n",idx,1,ans1);
    for(int i = 1;i < idx;i++){
        /*现在是,断开i~i+1时间*/
        ans1 = min(ans1,max(max(pre1[i],suf1[i + 1]),pre[i] + suf[i + 1] + wei[idx]));
// printf("%lld~%lld : %lld\n",i,i + 1,ans1);
    }
    printf("%lld\n",max(ans1,ans2));
// printf("ans1=%lld ans2=%lld\n",ans1,ans2);
// printf("idx = %lld\n",idx);
// for(int i = 1;i <= idx;i++){printf("val[%lld] = %lld, wei[%lld] = %lld\n",i,val[i],i,wei[i]);}
// for(int i = 1;i <= idx;i++){printf("pre[%lld] = %lld, pre1[%lld] = %lld\n",i,pre[i],i,pre1[i]);}
// for(int i = 1;i <= idx;i++){printf("suf[%lld] = %lld, suf1[%lld] = %lld\n",i,suf[i],i,suf1[i]);}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值