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. iOS 检测耳机插入/拔出

    http://www.verydemo.com/demo_c134_i28481.html 开发过程中录音和播放这块碰到了一些问题,麻烦的主要有三个: 检测是否有声音输入设备 当有多个声音输出设备时, ...

  2. openjudge dp水题记录

    当发现自己竟然不会打dp的时候内心是崩溃的,然后按照一年前的刷题记录刷openjudge,然后发现自己准确率比一年前(刚学信竞两个月时)的准确率低得多,已经没救. 列一下最近打的几道sb题 2985: ...

  3. 手动实现一个form组件

    最近研究了一下element-ui,想着手动实现一下里面的form组件,贴个组件里面的代码 <el-form :model="ruleForm" status-icon :r ...

  4. php 练习 1

    php5 echo 和 print 语句 在PHP 中, 有两种基本的输出方法:echo 和print . 在本教程中,我们几乎在每个例子中都会用到echo和print.因此,本节为您讲解更多关于这两 ...

  5. android完美的退出方法

    http://blog.csdn.net/get123/article/details/9001214

  6. @总结 - 1@ 多项式乘法 —— FFT

    目录 @0 - 参考资料@ @1 - 一些概念@ @2 - 傅里叶正变换@ @3 - 傅里叶逆变换@ @4 - 迭代实现 FFT@ @5 - 参考代码实现@ @6 - 快速数论变换 NTT@ @7 - ...

  7. oracle 和 mysql 遍历当前月份每一天

    获取当前月份的每一天的数据 oracle SELECT TO_DATE(TO_CHAR(SYSDATE, 'YYYYMM'), 'YYYYMM') + (ROWNUM - 1) DAY_ID FROM ...

  8. 洛谷P1616 疯狂的采药

    //完全背包 #include<bits/stdc++.h> using namespace std; ; ; int n,m,v[maxn],w[maxn],f[maxv]; int m ...

  9. 2019徐州网络赛 I.query

    这题挺有意思哈!!!看别人写的博客,感觉瞬间就懂了. 这道题大概题意就是,给一串序列,我们要查找到l-r区间内,满足min(a[ i ],a[ j ]) = gcd(a[ i ],a[ j ]) 其实 ...

  10. 通过Ajax提交form表单来提交上传文件

    Ajax 提交form方式可以将form表单序列化 然后将数据通过data提交至后台,例如: $.ajax({      url : "http://localhost:8080/" ...