CF1209

CF1209

CF1209A

link

CF1209A题意

给出一个长度为 n n n的序列 a 1 , a 2 , a 3 , . . .   , a n a_1,a_2,a_3,...\ ,a_n a1,a2,a3,... ,an,要求你使用最少的颜色对每个染色。对于任何颜色,满足:染成该颜色的数都能被染成该颜色的最小数整除。

比如 [ 40 , 60 , 10 ] [40,60,10] [40,60,10]可以被染成同一种颜色,因为它们都可以被 10 10 10整除。

每种颜色可以使用一次或多次。染成同一个颜色的所有元素不需要是连续的。请求出最少需要的颜色数量。

CF1209A题解

从小到大排序,然后强行染色即可

CF1209A代码

#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;
int n;
int a[maxn];
bool book[maxn];
signed main(){
    n = read();int cnt = 0;
    for(int i = 1;i <= n;i++){a[i] = read();}
    sort(a + 1,a + 1 + n);
    for(int i = 1;i <= n;i++){
        if(!book[i]){
            cnt++;
            for(int j = i;j <= n;j++){
                if(a[j] % a[i] == 0){
                    book[j] = 1;
                }
            }
        }
    }
    printf("%d\n",cnt);
    return 0;
}

CF1209D

link

CF1209D题意

n n n 种花, k k k 个客人,每个人喜欢两种编号不同的花。但是每种花在花店里只有一束。

客人按顺序进入花店,会买走所有她喜欢且仍在店铺里的花。如果一个客人买不到任何一束花,那么她就会十分沮丧导致变成肥宅。现在你可以自己安排这 k k k 个人的顺序,使得肥宅的数量最小。

CF1209D题解

如果将每个人喜欢的编号联边,会发现最后变成了 c n t cnt cnt 个联通块。
然后每个联通块如果进行排序,第一个人拿走两个,之后的人拿一个。
故能满足的人有 n − c n t n-cnt ncnt 个。
一共有 k k k 个人,故有 k − n + c n t k - n + cnt kn+cnt 个满足不了。
并查集维护下就完了。

CF1209D代码

#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 = 1e5 + 10;
int n, k;

int fa[maxn];
int getf(int x){return fa[x] == x ? x : fa[x] = getf(fa[x]);}

signed main(){
    n = read(); k = read();int u, v, cnt = 0;
    for(int i = 1;i <= n;i++)fa[i] = i;
    for(int i = 1;i <= k;i++){
        u = read(); v = read();
        int fu = getf(u), fv = getf(v);
        if(fu != fv){fa[fu] = fv;}
    }
    for(int i = 1;i <= n;i++){cnt += (fa[i] == i);}
    printf("%d\n",k - n + cnt);
    return 0;
}

CF1209E1 & E2

link

CF1209E题意

给出一个 n × m n\times m n×m 的矩阵(Eazy version n ≤ 4 , m ≤ 100 n\le4,m\le100 n4,m100,Hard version n ≤ 12 , m ≤ 2000 n\le12,m\le2000 n12,m2000),现在允许让每一列循环位移任意次,问各行最大值的和的最大值是多少?

CF1209E题解

首先必须发现的一个性质,就是有效的列最多只有n个。
因为如果按照每一列的最大值从大到小排序
那么最差的情况就是把前n列的最大值依次排开占满1~n行,后面的m-n列是无意义的。
到这里Eazy version就可以走了,因为最后就变成了一个 4 × 4 4\times4 4×4 的矩阵,爆搜每一列位移几次就完了。
我们来看Hard version( 1 ≤ n ≤ 12 1\le n\le12 1n12)怎么做。
如果设 f i , s t a f_{i,sta} fi,sta 表示第i列为止,让 s t a sta sta 中是1的位置是最大值的最大和,
那么就有 f i , s t a = max ⁡ f i − 1 , s t a 1 + w s t a ⊕ s t a 1 f_{i,sta} = \max{f_{i-1,sta_1} + w_{sta\oplus sta_1}} fi,sta=maxfi1,sta1+wstasta1
其中 w i w_{i} wi 表示将第i列位移任意次,i中是1的位置之和的最大值, s t a 1 sta_1 sta1 s t a sta sta 的子集。
但是这个时候可能产生一个问题,就是如果按照这种递推方式,如果第i个数字不是最大值咋整?
不慌,我们求得又不是最小值,如果第i个数不是最大值,那一定会有另一种状态比这种更优,故而这种不合法状态就在转移中消失了。
然后注意下w数组可以在转移之前预处理,不用每次转移的时候先算就没了。

CF1209 E1 & E2代码

#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 = 13, maxm = 2100;
int n, m;
struct COL{
    int row[maxn], mx;
    void init(){for(int i = 1;i <= n;i++)mx = max(mx,row[i]);}
    friend bool operator < (COL a,COL b){return a.mx > b.mx;}
}a[maxm];
int w[1 << maxn], f[maxn][1 << maxn];
signed main(){
int T = read();
while(T--){
    memset(a,0,sizeof(a));memset(w,0,sizeof(w));memset(f,0,sizeof(f));
    n = read(); m = read();
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
            a[j].row[i] = read();
    for(int i = 1;i <= m;i++){a[i].init();}
    sort(a + 1,a + 1 + m);
    for(int i = 1;i <= min(n, m);i++){
        for(int j = 0;j < (1 << n);j++){
            w[j] = 0;
            for(int k = 0;k < n;k++){
                int tmp = 0;
                for(int l = 1;l <= n;l++)
                    if(j & (1 << (l - 1)))
                        tmp += a[i].row[(l + k - 1) % n + 1];
                w[j] = max(w[j],tmp);
            }
        }
        for(int j = 0;j < (1 << n);j++){
            f[i][j] = f[i - 1][j];if(i == 1){f[i][j] = w[j];continue;}
            for(int k = j;k;k = (k - 1) & j) f[i][j] = max(f[i - 1][k] + w[k ^ j],f[i][j]);
        }
    }
    printf("%d\n",f[min(n, m)][(1 << n) - 1]);
}
    return 0;
}

CF1209F

link

CF1209F题意

n个点,m条边的无向图,保证联通,一条路径的长度定义为将经过的边的编号依次连接得到的十进制数字。
求出1到2~n的最短路 mod 1 0 9 + 7 10^9+7 109+7 的结果。

CF1209F题解

从未见过的建图方式
发现如果单单按照编号建边,发现这玩应不好跑最短路。
尝试将每条边按照十进制拆分,然后就好弄了。
直接bfs扩展就完了~~~~~吗?
想一个问题,bfs求最短路的优势是什么?
是可以保证距离小的先更新。
那距离相等的呢,怎么办?
好办,每次更新的时候把距离相等的一起更新就好了。

CF1209F代码

#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 = 5e5 + 10, mod = 1e9 + 7;
int n, m;
vector<vector<int> > que1, que2;
vector<int> edg[maxn * 2][11];int cnt;
void add(int u,int v,int id){
    while(id >= 10){
        edg[++cnt][id % 10].push_back(v);
        v = cnt;id /= 10;
    }
    edg[u][id].push_back(v);
}
int dis[maxn * 2];
bool book[maxn * 2];
signed main(){
    cnt = n = read(); m = read();int u, v;
    for(int i = 1;i <= m;i++){
        u = read(); v = read();
        add(u, v, i); add(v, u, i);
    }
    dis[1] = 0;
    vector<int> tmp;tmp.push_back(1);
    que1.push_back(tmp);book[1] = 1;
    while(!que1.empty()){
        for(auto x : que1){
            for(int d = 0;d < 10;d++){
                tmp.clear();
                for(int i : x){
                    for(int v : edg[i][d]){
                        if(!book[v]){
                            book[v] = 1;dis[v] = (dis[i] * 10LL + d) % mod;
                            tmp.push_back(v);
                        }
                    }
                }
                if(!tmp.empty()){que2.push_back(tmp);}
            }
        }
        que1 = que2; que2.clear();
    }
    for(int i = 2;i <= n;i++){printf("%lld\n",dis[i]);}
    return 0;
}

CF1209G1

link

CF1209G1题意

给你一个序列,每一个位置有一个颜色。
你每次可以将一个颜色A改成另一个颜色B(注意,所有颜色是A的都要转化成B),代价就是颜色是A的位置的数量。
问让所有相同颜色连续的最少代价是多少。

CF1209G1题解

不难发现,如果设第i中颜色出现的最左端是 L i L_i Li,最右端是 R i R_i Ri,那么所有相交的颜色都需要转化成相同的颜色。
然后每次找到一段相交端的最右端和出现次数最多的颜色数量,将所有颜色都变成这个颜色。
然后就没了。是的G1就这些

CF1209G1代码

#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 = 2e5 + 10;
int n, q;
int a[maxn];
int r[maxn], sum[maxn];
signed main(){
    n = read(); q = read();
    for(int i = 1;i <= n;i++){r[a[i] = read()] = i;sum[a[i]]++;}
    int i = 1, res = 0;
    while(i <= n){
        int mxr = i, mxsum = 0;
        while(i <= mxr){
            mxr = max(mxr,r[a[i]]);
            mxsum = max(mxsum,sum[a[i]]);
            i++;
        }
        res += mxsum;
    }
    printf("%d\n",n - res);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值