codeforces-1140 (div2)

时间:2024-01-08 15:28:08

A.维护一个前缀最大值,不断跳即可

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 1e4 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
int a[maxn];
int Max[maxn];
int main(){
Sca(N);
for(int i = ; i <= N ; i ++){
Sca(a[i]);
a[i] = max(a[i],a[i - ]);
}
int cnt = ;
int now = ;
while(now < N){
cnt++;
now++;
while(now != a[now]) now = a[now];
}
Pri(cnt);
return ;
}

A

B.从左边开始删除一直删到>或者从右边开始删除一直删到<,两种方案取最小值。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
char str[maxn];
int main(){
int T = read();
while(T--){
Sca(N);
scanf("%s",str + );
int ans = N - ;
for(int i = ; i <= N ; i ++){
if(str[i] == '>'){
ans = min(ans,i - );
break;
}
}
for(int i = N ; i >= ; i --){
if(str[i] == '<'){
ans = min(ans,N - i);
break;
}
}
Pri(ans);
}
return ;
}

B

C.按照beauty值从大到小排序,维护一个前缀和(最多K个length),小根堆维护一下每次要踢出哪个最小lenght的弟弟

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 3e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
PLL P[maxn];
bool cmp(PLL a,PLL b){
return a.se > b.se;
}
int main(){
Sca2(N,K);
for(int i = ; i <= N; i ++){
scanf("%lld%lld",&P[i].fi,&P[i].se);
}
sort(P + ,P + + N,cmp);
priority_queue<LL,vector<LL>,greater<LL>>Q;
LL sum = ;
LL ans = ;
for(int i = ; i <= N ; i ++){
ans = max(ans,(sum + P[i].fi) * P[i].se);
Q.push(P[i].fi); sum += P[i].fi;
if(Q.size() >= K){
sum -= Q.top();
Q.pop();
}
}
Prl(ans);
return ;
}

C

D.发现1,2,3| 1,3,4| 1,4,5 .. |1,n - 1,n为最优解。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 3e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K; int main(){
Sca(N);
LL sum = ;
for(int i = ; i < N ; i ++){
sum += i * (i + );
}
Prl(sum);
return ;
}

D

E*

1.发现不存在奇长度的回文串只需要满足不存在长度3的回文串即可,长度为5的回文串包含了长度3的回文串。

2.也就是说,要满足所有的str[x] != str[x + 2],发现奇偶位置上的数字其实互不干扰,那可以把序列分成两个序列来做。

3.得到dp方程,dp[i][j]表示到了i这个位置,且这个位置上的数字为j的时候,满足条件序列的总数,状态转移方程为dp[i][j] = ∑dp[i - 1][p] (1 <= p <= K && p != j)

4.当然这个时间复杂度和空间复杂度双双nk的算法是行不通的,我们发现对于i相同的dp[i][j],只会有两种不同的值,并且是其中k - 1个值相同以及另一个值鹤立鸡群的情况(当然也有可能都是鸡完全相同)

5.考虑标注特殊的点位置和特殊的点值以及k - 1个其他的点值,即可压缩复杂度为O(n)

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 2e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = ;
int N,M,K;
LL a[maxn],b[maxn];
LL solve(LL *x,int n){
LL big,small,pos;
if(x[] == -){
big = ; small = ; pos = ;
}else{
big = ; small = ; pos = x[];
}
for(int i = ; i <= n ; i ++){
if(x[i] == -){
LL s = big * (K - ),b = big * (K - ) + small;
small = s % mod; big = b % mod;
}else{
if(pos == x[i]){
small = big * (K - ) % mod;
big = ;
}else{
small = big * (K - ) + small; small %= mod;
pos = x[i];
big = ;
}
}
}
return (small + big * (K - )) % mod;
}
int main(){
Sca2(N,K);
int cnt1 = ,cnt2 = ;
for(int i = ; i <= N ; i ++){
if(i & ) a[++cnt1] = read();
else b[++cnt2] = read();
}
Prl(solve(a,cnt1) * solve(b,cnt2) % mod);
return ;
}

E

F*

1.考虑将两个集合用一个二维的表来表示,添加就是将i行j列合并,最终答案是每个联通块的行数 * 列数。

2.考虑到用并查集,size1[maxn],size2[maxn],分别表示这个集合里面行列的数量。

3.问题在于删除,并查集是不存在在线直接删除这种黑科技的,但是我们可以用离线的方式,将并查集的存在生命周期放到线段树上,然后dfs整颗线段树进行优化。

这个操作在BZOJ2049里遇到过了,当时还写了blog https://www.cnblogs.com/Hugh-Locke/p/10367480.html

结果这次还是翻皮水了(雾)

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 6e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
map<PII,int>P;
//并查集
int fa[maxn];
LL size1[maxn],size2[maxn];
int dep[maxn];
void init(){
for(int i = ; i < maxn; i ++){
fa[i] = i;
if(i > 3e5) size2[i] = ;
else size1[i] = ;
dep[i] = ;
}
}
//线段树
struct Edge{
PII to;
int next;
}edge[maxn * ];
int tot;
void add(int& t,PII w){
edge[tot].to = w;
edge[tot].next = t;
t = tot++;
}
struct Tree{
int l,r;
int head;
}tree[maxn << ];
void Build(int t,int l,int r){
tree[t].l = l; tree[t].r = r;
tree[t].head = -;
if(l == r) return;
int m = l + r >> ;
Build(t << ,l,m); Build(t << | ,m + ,r);
}
void add(int t,int l,int r,PII w){
if(l <= tree[t].l && tree[t].r <= r){
add(tree[t].head,w);
return;
}
int m = tree[t].l + tree[t].r >> ;
if(r <= m) add(t << ,l,r,w);
else if(l > m) add(t << | ,l,r,w);
else{
add(t << ,l,m,w); add(t << | ,m + ,r,w);
}
}
int Stack[maxn],top;
int find(int x){
while(fa[x] != x) x = fa[x];
return x;
}
LL ans;
void rewind(int t){
while(top > t){
int x = Stack[--top];
dep[fa[x]] -= dep[x] + ;
ans -= 1LL * size1[fa[x]] * size2[fa[x]];
size1[fa[x]] -= size1[x];
size2[fa[x]] -= size2[x];
ans += 1LL * size1[fa[x]] * size2[fa[x]];
ans += 1LL * size1[x] * size2[x];
fa[x] = x;
}
}
void dfs(int t){
int now = top;
for(int i = tree[t].head; ~i ; i = edge[i].next){
PII t = edge[i].to;
t.fi = find(t.fi); t.se = find(t.se);
if(t.fi == t.se) continue;
if(dep[t.fi] > dep[t.se]) swap(t.fi,t.se);
Stack[top++] = t.fi;
fa[t.fi] = t.se;
dep[t.se] += dep[t.fi] + ;
ans -= 1LL * size1[t.fi] * size2[t.fi]; ans -= size1[t.se] * size2[t.se];
size1[t.se] += size1[t.fi]; size2[t.se] += size2[t.fi];
ans += 1LL * size1[t.se] * size2[t.se];
}
if(tree[t].l == tree[t].r){
printf("%lld ",ans);
}else{
dfs(t << );
dfs(t << | );
}
rewind(now);
}
int main(){
Sca(N); init();
Build(,,N);
for(int i = ; i <= N; i ++){
PII p; p.fi = read(),p.se = read() + 3e5;
if(P[p]){
add(,P[p],i - ,p);
P[p] = ;
}else P[p] = i;
}
for(map<PII,int>::iterator it = P.begin(); it != P.end(); it++) if((*it).se) add(,(*it).se,N,(*it).fi);
dfs();
return ;
}

F