[比赛链接](Dashboard - Educational Codeforces Round 150 (Rated for Div. 2) - Codeforces)
文章目录
- A.[Game with Board](https://codeforces.com/contest/1841/problem/A)
- B.[Keep it Beautiful](https://codeforces.com/contest/1841/problem/B)
- C.[Ranom Numbers](https://codeforces.com/contest/1841/problem/C)
- D.[Pairs of Segments](https://codeforces.com/contest/1841/problem/D)
- E.[Fill the Matrix](https://codeforces.com/contest/1841/problem/E)
A.Game with Board
n>=5先手赢,否则后手赢
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n,m;
int a[500005];
void solve(){
scanf("%lld",&n);
if(n>=5)printf("Alice\n");
else printf("Bob\n");
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}
B.Keep it Beautiful
当一个序列可以拆分成两段非递减序列,且第二段非递减序列的结尾要大于第一段的开头则这个序列是“美丽的”,维护这个过程,当第一次(出现递减且小于等于第一个数时),把这个数当作第二段非递减数的开头,后面的数要满足大于当前队尾且小于等于第一个数。
所以答案为1的数是,第一段非递减序列和第二段非递减序列,其它答案为0
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n;
int t;
void solve(){
int now=0;
int ok=-1;
scanf("%lld",&n);
int fir=-1;
for(int i=1;i<=n;i++){
scanf("%lld",&t);
if(i==1)fir=t;
if(t>=now){
if(ok==-1){
printf("1");
now=t;}
else{
if(t<=fir){
printf("1");
now=t;
}
else{
printf("0");
}
}
}
else{
if(ok==-1&&t<=fir){
ok=1;
printf("1");
now=t;
}
else{
printf("0");
}
}
}
printf("\n");
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}
C.Ranom Numbers
大模拟,先处理一个后缀字母最大值,以及后缀在没有修改的条件下的和。
然后从0到n枚举每一位改成每一位数,在这个过程中维护一个类似单调栈的东西,就是加入一个字母,将小于这个字母的值都改为负,再将正的当前字母加入。
当枚举到第i位,作为第j个字母时,i及i以后的最大的字母是max(j,i+1的后缀最大值),[i+1,n]的和通过后缀和算出,i的值通过后缀最大值讨论出正负,前面直接负的值直接加上,前面目前仍是正的值通过与i及i以后的最大的字母的关系得到正负,最后把这些加到一起得到答案取max
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int z[10];
int q[200015];
int a[200015];
int c[200015];
int ho[200015];
int b[10];
map<char,int>p;
string s;
int now=0;
int cal(int l,int r){
if(l>r)return 0;
return q[r]-q[l-1];
}
void add(int k){
for(int i=1;i<k;i++){
now-=b[i]*z[i];
z[i]=0;
}
z[k]++;
}
void solve(){
memset(z,0,sizeof(z));
int ans=-1e18;
cin>>s;
ho[s.size()]=0;
for(int i=s.size()-1;i>=0;i--){
ho[i]=max(ho[i+1],(int)(s[i]-'A'+1));
}
for(int i=0;i<s.size();i++){
a[i]=p[s[i]];
if(s[i]-'A'+1>=ho[i+1]){
c[i]=1;
}
else {
c[i]=-1;
}
}
q[0]=a[0]*c[0];
for(int i=1;i<s.size();i++){
q[i]=q[i-1]+a[i]*c[i];
}
ans=q[s.size()-1];
now=0;
for(int i=0;i<s.size();i++){
for(int j=1;j<=5;j++){
int temp=cal(i+1,s.size()-1)+now;
int li=max(j,ho[i+1]);
for(int k=1;k<li;k++){
temp-=z[k]*b[k];
}
for(int k=li;k<=5;k++){
temp+=z[k]*b[k];
}
if(j>=ho[i+1])temp+=b[j];
else temp-=b[j];
ans=max(ans,temp);
}
add(s[i]-'A'+1);
}
printf("%lld\n",ans);
}
signed main(){
p['A']=1;
p['B']=10;
p['C']=100;
p['D']=1000;
p['E']=10000;
b[1]=1;
b[2]=10;
b[3]=100;
b[4]=1000;
b[5]=10000;
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}
D.Pairs of Segments
DP
先将线段按照r递增排序,预处理f[i],表示r<i.l 的最大下标
DP[i]表示前i个里最多选了多少个线段
D
P
[
i
]
=
m
a
x
(
D
P
[
i
−
1
]
,
D
P
[
m
i
n
(
f
[
i
]
,
f
[
j
]
)
]
+
2
)
(
线段
i
和线段
j
有交集
)
DP[i]=max(DP[i-1],DP[min(f[i],f[j])]+2)(线段i和线段j有交集)
DP[i]=max(DP[i−1],DP[min(f[i],f[j])]+2)(线段i和线段j有交集)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
struct node{
int l,r;
};
bool cmp(node A,node B){
return A.r<B.r;
}
int dp[2005];
int f[2005];
int n;
node a[2005];
void solve(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld %lld",&a[i].l,&a[i].r);
dp[i]=0;
f[i]=0;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i].r<a[j].l){
f[j]=i;
}
}
}
for(int i=1;i<=n;i++){
dp[i]=dp[i-1];
for(int j=1;j<i;j++){
if(a[j].r>=a[i].l){
dp[i]=max(dp[i],dp[min(f[i],f[j])]+2);
}
}
}
printf("%lld\n",n-dp[n]);
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}
E.Fill the Matrix
我好像使用了特别麻烦的做法。
线段树
要找到所有相连的最长线段,然后从长到短选择
首先取
a
[
i
]
=
n
−
a
[
i
]
a[i]=n-a[i]
a[i]=n−a[i]
然后从1开始枚举,找到从当前点开始最远的区间没有0的区间,再找到这个区间的最小值,再把这个区间减掉这个区间最小值,同时长度为这个区间的线段个数加上这个最小值,重复这个过程直到这个点为0,所有操作均可用线段树O(logn)实现,最多修改n次(每次都会使至少一个变为0),即最多n次这个过程
最后再从大到小枚举线段长度统计答案
总复杂度:O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n,m;
int a[200005];
int ans;
int tr1[800005];//最小值
int la[800005];
int f[200005];
void build(int k,int l,int r){
la[k]=0;
if(l==r){
tr1[k]=a[l];
return;
}
int mid=(l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
tr1[k]=min(tr1[k*2],tr1[k*2+1]);
}
void update(int k){
tr1[k]=min(tr1[k*2],tr1[k*2+1]);
}
void pushdown(int k,int l,int r){
tr1[k*2]+=la[k];
la[k*2]+=la[k];
tr1[k*2+1]+=la[k];
la[k*2+1]+=la[k];
la[k]=0;
}
void xi(int k,int l,int r,int l1,int r1,int w){
if(l>=l1&&r<=r1){
tr1[k]+=w;
la[k]+=w;
return;
}
pushdown(k,l,r);
int mid=(l+r)/2;
if(l1<=mid)xi(k*2,l,mid,l1,r1,w);
if(r1>mid)xi(k*2+1,mid+1,r,l1,r1,w);
update(k);
}
int fin(int k,int l,int r,int to){
if(l==r){
return tr1[k];
}
pushdown(k,l,r);
int mid=(l+r)/2;
int temp;
if(to<=mid)temp=fin(k*2,l,mid,to);
else temp=fin(k*2+1,mid+1,r,to);
update(k);
return temp;
}
int fin1(int k,int l,int r,int ls){//找>=ls第一个等于0的下标 ,没找到返回0
if(tr1[k]>0)return 0;
if(l>=ls){
if(l==r)return l;
pushdown(k,l,r);
int mid=(l+r)/2;
if(tr1[k*2]==0)return fin1(k*2,l,mid,ls);
return fin1(k*2+1,mid+1,r,ls);
}
pushdown(k,l,r);
int mid=(l+r)/2;
int temp=0;
if(mid>=ls)temp=fin1(k*2,l,mid,ls);
if(!temp)temp=fin1(k*2+1,mid+1,r,ls);
update(k);
return temp;
}
int fin2(int k,int l,int r,int l1,int r1){
if(l>=l1&&r<=r1){
return tr1[k];
}
pushdown(k,l,r);
int mid=(l+r)/2;
int temp=1e9;
if(l1<=mid)temp=min(temp,fin2(k*2,l,mid,l1,r1));
if(r1>mid)temp=min(temp,fin2(k*2+1,mid+1,r,l1,r1));
update(k);
return temp;
}
int num=0;
void solve(){
num++;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]=n-a[i];
f[i]=0;
}
scanf("%lld",&m);
build(1,1,n);
ans=0;
for(int i=1;i<=n;i++){
int now=fin(1,1,n,i);
if(!now)continue;
while(now){
int te=fin1(1,1,n,i);
if(te==0)te=n;
else te--;
int sq=fin2(1,1,n,i,te);
f[te-i+1]+=sq;
xi(1,1,n,i,te,-sq);
now-=sq;
}
}
for(int i=n;i>0;i--){
if(f[i]*i<=m){
ans+=f[i]*(i-1);
m-=f[i]*i;
}
else{
int st=m/i;
ans+=st*(i-1);
m-=st*i;
if(m>1)ans+=m-1;
m=0;
}
}
printf("%lld\n",ans);
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}