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. Oracle使用——impdp导入数据时数据表已经存在

    背景 在做数据迁移时,需要将不同地方的dmp文件整合到一个数据库中,在导入时,目标表已经存在,该如何把数据追加进入目标表中 方法介绍 当使用IMPDP完成数据库导入时,如遇到表已存在时,Oracle提 ...

  2. 你在用 JWT 代替 Session?

    现在,JSON Web Tokens (JWT) 是非常流行的.尤其是 Web 开发领域. 流行 安全 稳定 易用 支持 JSON 所有这些因素,令 JWT 名声大振. 但是,今天我要来说说使用 JW ...

  3. F4NNIU 整理的 docker-compose 几个常用命令

    F4NNIU 整理的 docker-compose 几个常用命令 up 创建并启动一个容器. 记录一下,如果已经有容器,up 和 start 都可以启动容器,up 可以看到调试窗口,但是 start ...

  4. UITextField 自定义clearButton背景色

    一个鸡贼的解决方案,适用于自定义clearButton的样式,直接修改背景图即可 1. 实现基于UITextField的category并添加如下方法及声明 - (void)setLightStyle ...

  5. 2013年山东省第四届ACM大学生程序设计竞赛J题:Contest Print Server

    题目描述     In ACM/ICPC on-site contests ,3 students share 1 computer,so you can print your source code ...

  6. 洛谷1758 BZOJ1566 管道取珠题解

    题目链接 一道人类智慧的dp题 首先我们可以将∑ai^2转化为求取两次,两次一样的方案数 然后用f[i][j][k][l]表示第一个人在第一个串中取到i第二个串中取到j 第二个人在一个串中取到k第二个 ...

  7. Maven启用代理访问

    如果你的公司正在建立一个防火墙,并使用HTTP代理服务器来阻止用户直接连接到互联网.如果您使用代理,Maven将无法下载任何依赖. 为了使它工作,你必须声明在 Maven 的配置文件中设置代理服务器: ...

  8. Django框架登录验证及产生随机验证码的实例

    1:views视图代码 # 登录验证 def login(request): # 使用ajax请求可以使用判断 # if request.is_ajax(): if request.method == ...

  9. 关于使用 Java 分片读\写文件

    分片读取文件方法: /** * 分片读取文件块 * * @param path 文件路径 * @param position 角标 * @param blockSize 文件块大小 * @return ...

  10. python 空值(NoneType)