CF1209

A B

水题不管

C

因为要求最终整个序列是要单调的

所以我们就考虑枚举断点\(x\)

之后把\(<x\)的数放到第一个集合

把\(> x\)的数放到第二个集合

至于\(=x\)的数

他能放到第一个集合当且仅当后面没有\(<x\)的数

否则就必须放到第二个集合

在放的时候判断合法性即可

(枚举把\(0-9\)写成了\(1 - 10\)就没了QAQ

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
char s[N];
int a[N];
int sum[N][11];
int belong[N];
int n;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline bool check(int x){
// printf("x::%d\n",x);
int now1 = -1,now2 = -1;
for(int i = 1;i <= n;++i){
// printf("%d %d %d\n",i,now1,now2);
if(a[i] < x && a[i] < now1) return 0;
if(a[i] > x && a[i] < now2) return 0;
if(a[i] != x){
if(a[i] < x) now1 = max(now1,a[i]),belong[i] = 1;
else if(a[i] > x) now2 = max(now2,a[i]),belong[i] = 2;
}
if(a[i] == x){
bool flag = 0;
for(int j = 0;j <= x - 1;++j) if(sum[i][j]) flag = 1;
if((!flag) && (a[i] >= now1)) {
now1 = a[i],belong[i] = 1;
}
else{
if(now2 > a[i]) return 0;
now2 = max(now2,a[i]),belong[i] = 2;
}
}
}
return 1;
}
int main(){
int T = read();
while(T--){
bool flag = 0;
n = read();
scanf("%s",s + 1);
for(int i = 1;i <= n;++i) a[i] = s[i] - '0';
for(int i = n;i >= 1;--i){
for(int j = 0;j <= 9;++j) sum[i][j] = sum[i + 1][j];
sum[i][a[i]]++;
}
for(int i = 0;i <= 9;++i){
if(check(i)){
for(int j = 1;j <= n;++j) printf("%d",belong[j]);
printf("\n");
flag = 1;
break;
}
}
if(!flag) printf("-\n");
for(int i = 1;i <= n;++i){
for(int j = 0;j <= 9;++j) sum[i][j] = 0;
}
}
return 0;
}
 

D

首先我们发现把\(a_i\)向\(b_i\)连边最后会形成若干个连通块

每个连通块的大小 - 1就是这个连通块的贡献

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
struct node{
int ai;
int bi;
}a[N];
vector <int> G[N];
int n,k;
bool flag1[N],flag2[N]; inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
queue <int> q;
int ans = 0;
inline void dfs(int x){
flag1[x] = 1;ans++;
for(int i = 0;i < (int)G[x].size();++i){
int y = G[x][i];
if(!flag1[y]) dfs(y);
}
}
int main(){
n = read(),k = read();
for(int i = 1;i <= k;++i){
a[i].ai = read();
a[i].bi = read();
G[a[i].ai].push_back(a[i].bi);
G[a[i].bi].push_back(a[i].ai);
}
for(int i = 1;i <= n;++i) if(!flag1[i]) ans--,dfs(i);
cout << k - ans;
}

E1E2

首先观察发现\(n\)特别小,当一个数小于等于\(20\)的时候第一反应就是要考虑状压

一个特别重要的性质

我们把所有的列按照这一列的最大值从大到小跑徐之后

最多只有前\(n\)列有用

也就是说

$n\times m \(的矩阵变成了\)n \times n$的

我们设\(f_{i,S}\)表示前\(i\)列,\(S\)这个状态对应的行的最大值已经确定的最大贡献,

\(g_{i,S}\)表示从第\(i\)列取出能够表示\(S\)这个集合的最大值

转移

\[f_{i,S} = \max_{T\subseteq S} f_{i - 1,S - T}+g_{i,T}
\]

记下来考虑怎么求\(g\)

由于存在轮换的存在

我们枚举一个集合,然后把这个集合能够表示的所有的状态都尝试用这个集合的值去更新

比如

\(1101\)能够表示\(1101\),\(1110\),\(1011\),\(0111\)

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int M = 21;
const int N = 2003;
int a[M][N];
int b[M][M];
int n,m;
int f[13][(1 << 13) + 5];
int g[13][(1 << 13) + 3];
struct node{
int maxx;
int id;
}row[N];
inline bool cmp(node x,node y){
return x.maxx > y.maxx;
}
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
int T = read();
while(T--){
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
memset(row,0,sizeof(row));
n = read(),m = read();
for(int i = 1;i <= n;++i){
for(int j = 1;j <= m;++j){
a[i][j] = read();
row[j].maxx = max(row[j].maxx,a[i][j]);
row[j].id = j;
}
}
sort(row + 1,row + m + 1,cmp);
m = min(n,m);
for(int i = 1;i <= n;++i){
for(int j = 1;j <= m;++j)
b[i][j] = a[i][row[j].id];
}
for(int j = 1;j <= m;++j){
for(int i = 1;i < (1 << n);++i){
int res = i;
int sum = 0;
for(int h = 0;h < n;++h) if(res & (1 << h)) sum += b[h + 1][j];
for(int k = 0;k < n;++k){
g[j][res] = max(g[j][res],sum);
int nn = res;
res = ((nn >> (n - 1)) & 1) | ((nn << 1) & ((1 << n) - 1));
}
}
}
for(int i = 0;i < m;++i){
for(int j = 0;j < (1 << n);++j){
int S = ((1 << n) - 1) ^ j;
f[i + 1][j] = max(f[i + 1][j],f[i][j]);
for(int son = S;son;son = (son - 1) & S){
f[i + 1][j | son] = max(f[i + 1][j | son],f[i][j] + g[i + 1][son]);
}
}
}
printf("%d\n",f[m][(1 << n) - 1]);
}
return 0;
}

G1

我们发现,如果存在这种东西

3 1 3 1 3

那么整个区间最终都会是同一个数

也就是说

我们设\(l_i\)表示\(i\)的第一次出现的位置,\(r_i\)表示\(i\)最后一次出现的位置

最后会出现这种情况

我们发现有交集的区间最终都会变成同一个数,变成那个数取决于这个区间中那个数出现次数最多

我们把所有的区间搞出跑一跑贪心

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
int a[N];
int fir[N],las[N];
int sum[N];
int n,q;
bool flag1 = 1,flag2 = 1;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int ans = 0x3f3f3f3f;
struct node{
int li;
int ri;
int id;
};
vector <node> G;
inline bool cmp(node x,node y){
return x.li < y.li || (x.li == y.li && x.ri > y.ri);
}
int main(){
n = read(),q = read();
for(int i = 1;i <= n;++i){
a[i] = read();
if(!fir[a[i]]) fir[a[i]] = i;
las[a[i]] = i;
sum[a[i]]++;
}
for(int i = 1;i <= 200000;++i){
if(!fir[i]) continue;
if(!las[i]) G.push_back((node){fir[i],fir[i],i});
else G.push_back((node){fir[i],las[i],i});
}
sort(G.begin(),G.end(),cmp);
int ans = 0;
int now = 0;
int nowr = -1;
int len = 0;
int from = 1;
int maxx = 0;
// for(int i = 0;i < (int)G.size();++i){
// printf("%d %d %d\n",G[i].id,G[i].li,G[i].ri);
// }
while(now < G.size()){
if(G[now].li > nowr){
ans += nowr - from + 1 - maxx;
from = nowr + 1;
maxx = 0;
maxx = max(maxx,sum[G[now].id]);
nowr = G[now].ri;
}
else{
nowr = max(nowr,G[now].ri);
maxx = max(maxx,sum[G[now].id]);
}
now++;
}
ans += nowr - from + 1 - maxx;
printf("%d\n",ans);
return 0;
}
 

CF1209的更多相关文章

  1. CF1209题解

    E 每列都可以沿下滚动若干次,使得各行最大值之和最大 对每列的元素计算最大值,降序排,显然取前\(min(n,m)\)个列处理即可 比较巧妙的动规,设\(f(i,S)\)为前\(i\)列,已经确定最大 ...

随机推荐

  1. KiCad EDA 如何修改 Pcbnew 线路板的背景色?

    KiCad EDA 如何修改 Pcbnew 线路板的背景色? 关于背景色,传统的原理图是白色,线路板是黑色. EDA 软件 类型 颜色 Protel 原理图 浅黄色 Protel PCB 黑色 Orc ...

  2. Activity基本类分析

    先上一张类图. Android源码分析的文章在网络上已经很多, 有些知识点阅读完之后能够基本理解其框架,但是由于不是这些代码的维护者,所以过一段时间后就忘记的差不多了,又需要反复学习. 所以在读完文章 ...

  3. 2017 校赛 问题 B: CZJ-Superman

    题目描述 “那是只鸟?那是飞机?那是——超人!” 程序员在看完<CZJ-Superman>之后,励志要成为一名“CZJ-Superman”,学会了两个特殊技能ZZZ和JJJ,足以成为一名“ ...

  4. oracle一些常见的问题

    对于权限审计和大部分语句,by session无效,无论指定by session/by access还是不指定,审计都自动为by access. 审计的语句级可以指定ALL,但是ALL只包括大部分语句 ...

  5. HZOJ Drink

    神仙题,打了个whs式暴力卡常卡A了(我没脸),正解还是要打的,然而作者的题解看不懂…… Drink: 看惯了罗马音的小朋友们都会知道r发l的音,题目名:D Link. 每次修改都会改变O( N ^  ...

  6. Vue.js 第3章 axios&Vue过渡动画

    promise 它将我们从回调地狱中解脱出来 创建和使用 var fs = require('fs') // 创建promise // reslove表示执行成功后调用的回调函数 // reject表 ...

  7. L05 Laravel 教程 - 电商实战

    https://laravel-china.org/courses/laravel-shop https://laravel-china.org/topics/13206/laravel-shop-c ...

  8. mysql数据库之表和库

    SQL:语句主要用于存储数据,查询数据,更新数据和管理关系数据库系统SQL语言有IBM开发,sql语言分为中类型: 1.DDL语句 数据库定义语句:数据库,表,视图,索引,存储过程,例如create, ...

  9. @noi.ac - 491@ explore

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 最近有一个巨大的古代地下遗迹在比特镇被发现.这个地下遗迹的俯视图 ...

  10. 本地运行angularjs应用,提示出现跨域问题

    应用介绍: 使用angularjs创建一个简单的公司员工管理页面 使用Chrome打开后,提示存在跨域问题. 和别人交流后,得知使用像Angular,React,Vue框架,在Chrome地址栏中输入 ...