Preface
本来没准备打这场比赛的,因为昨天出去high玩了一整天才发现今天才发现晚上有CF,遂报名rush一发
结果今天状态有点崩,先是B看错题导致浪费时间,然后又是D自己叉自己把原来对的思路扔了
最后一看E真NM可做,结果写了个复杂度错的代码(只能跑随机数据)直接凉凉,12:10分为了不影响室友睡觉直接开溜
但由于本身的Rating不高,因此没有掉分也是万幸
A. Planets
SB题,对于每个机场判断下用那种方法销毁飞机即可
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,c,a[N],num[N],ans;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d%d",&n,&c),i=1;i<=n;++i)
scanf("%d",&a[i]),++num[a[i]];
for (ans=0,i=1;i<=100;++i) ans+=min(num[i],c);
for (i=1;i<=100;++i) num[i]=0;
printf("%d\n",ans);
}
return 0;
}
B. Meeting on the Line
刚开始看错题以为总时间最短,以为是个SB题
后来发现怎么样例输出怎么有小数,遂仔细读题发现还是个SB题
一眼二分答案\(T\),检验的话考虑\(left=T-t_i\)就是每个人除去准备的时间剩下的最大走路时间
因此对第\(i\)个人来说,\(x_0\)可能的位置只能在\([x_i-left,x_i+left]\)中,把每个人的可能区间并起来看看是否为空集即可
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
const double EPS=1e-8;
struct itv
{
double l,r;
}; int t,n,a[N],tim[N];
inline void merge(itv& A,const itv& B)
{
A=(itv){max(A.l,B.l),min(A.r,B.r)};
}
inline bool check(const double& T)
{
itv cur=(itv){-1e9,1e9}; for (RI i=1;i<=n;++i)
{
double left=T-tim[i]; if (left<0) return 0;
merge(cur,(itv){1.0*a[i]-left,1.0*a[i]+left});
}
return cur.r-cur.l>-EPS;
}
inline double getans(const double& T)
{
itv cur=(itv){-1e9,1e9}; for (RI i=1;i<=n;++i)
{
double left=T-tim[i]; if (left<0) return 0;
merge(cur,(itv){1.0*a[i]-left,1.0*a[i]+left});
}
return cur.l;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=n;++i) scanf("%d",&tim[i]);
double L=0,R=2e8,mid,ans; while (R-L>EPS)
if (check(mid=(L+R)/2.0)) ans=mid,R=mid; else L=mid;
printf("%.8lf\n",getans(ans));
}
return 0;
}
C. Minimum Notation
有点技巧的贪心题
首先simple地考虑,肯定应该先把所有的0
保留并放到最前面,这样的话我们需要把最后一个0
前面出现的所有非零数全部删除
考虑最后处理这些被删除的数,显然把他们从小到大扔在最后面即可
那么在处理0
时,若最后一个0
后面还有其它字符怎么办呢,显然直接在其中重复找1
的过程即可,当1
找完后若还剩下就找2
,以此类推
写个函数处理非常简便
#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
char s[N]; int t,n,ct[10];
inline void solve(CI pos,const char& ch)
{
if (pos>n||ch>'9') return; RI i; int lst=-1;
for (i=pos;i<=n;++i) if (s[i]==ch) lst=i;
if (!~lst) return solve(pos,ch+1);
for (i=pos;i<=lst;++i) if (s[i]==ch) ++ct[ch-'0']; else ++ct[min(9,s[i]-'0'+1)];
solve(lst+1,ch+1);
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; for (i=0;i<10;++i) ct[i]=0;
scanf("%s",s+1); n=strlen(s+1); solve(1,'0');
for (j=0;j<10;++j) for (i=1;i<=ct[j];++i) putchar(j+'0'); putchar('\n');
}
return 0;
}
D. Prefixes and Suffixes
妈的本来都做出来了撒泡尿回来脑抽了把写了一半的代码删了,真想抽自己一个大耳光子
首先我们发现对于\(a_i\),它和\(b_{n-i+1}\)的相对位置还是一样的,即每次操作这两个数要么一起换要么一起不换
因此这两个数不能出现在同一个串中,但它们的顺序和位置是可以任意换的(手玩一下即可)
因此我们把每个\(a_i\)和\(b_{n-i+1}\)看作一个无序对\((x,y),x\le y\),统计每种无序对的个数
考虑构造一种合法方案,不难发现每个\((x,y),x\ne y\)的无序对的个数必须是偶数,然后类似回文地排布构造即可
若\(n\)为奇数,则\((x,y),x=y\)的个数等于\(1\)是合法的,否则不合法;若\(n\)为偶数,则\((x,y),x=y\)的个数只能为\(0\)
#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,S=26;
int t,n,c[S][S]; char a[N],b[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; scanf("%d%s%s",&n,a+1,b+1); memset(c,0,sizeof(c));
for (i=1;i<=n;++i)
{
int x=a[i]-'a',y=b[n-i+1]-'a'; if (x>y) swap(x,y); ++c[x][y];
}
bool flag=1; for (i=0;i<S;++i) for (j=i+1;j<S;++j)
if (c[i][j]&1) flag=0; if (!flag) { puts("NO"); continue; }
int sum=0; for (i=0;i<S;++i) sum+=c[i][i]%2;
puts(sum>n%2?"NO":"YES");
}
return 0;
}
E. Maximums and Minimums
简单地提一下我比赛时的idea吧,今天有点晚了先懒得看官方sol了
首先这种区间最大最小值的经典套路无非两种,单调栈或笛卡尔树,但笛卡尔树有一个显著的问题,在处理了其中一个后不好处理另一个(也许是我理解烂,若有方法实现务必请指教)
因此我们考虑单调栈,找出以每个\(a_i\)为最小值时的最大扩展区间,当时naive地以为区间长度总和是\(O(n)\)级别的,然后T了
其实仔细想想也是,如果放在笛卡尔树上这部分相当于所有子树的size和,显然如果树极不平衡(如退化成链)则总和是\(O(n^2)\)级别的
因此也说明了为什么我们在利用笛卡尔树处理问题时通常要加上启发式合并和DSU on tree的姿势了,不然复杂度是会爆炸的
说回正题,先不考虑复杂度,此时我们应该如何统计答案,由于还要考虑区间最大值,因此我们从\(a_i\)开始,向左右两边统计前缀最大值
考虑在\([L_i,i],[i,R_i]\)(\(L_i,R_i\)分别为\(a_i\)的最大扩展区间的左右端点)中各取一个前缀最大值,二者的最大值即为区间的最大值
现在先考虑在\([i,R_i]\)中枚举每一个前缀最大值\(pfx_j\),分情况讨论:
- \(a_i|pfx_j\),此时在\([L_i,i]\)中合法的\(pfx_k\)为那些小于等于\(pfx_j\)的数量以及\(a_i|pfx_k\)且\(pfx_k>pfx_j\)的数量之和
- \(a_i\nmid pfx_j\),此时在\([L_i,i]\)中合法的\(pfx_k\)为那些\(a_i|pfx_k\)且\(pfx_k>pfx_j\)的数量
显然可以开两个树状数组来维护\([L_i,i]\)中的信息,一个维护是\(a_i\)的倍数的一个维护不是\(a_i\)的倍数的
设区间总长度为\(S\),总复杂度为\(O(S\log a_i)\)(当数据随机时\(S=n\log n\)跑得飞快,随便过几十万的数据点)
#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=500005;
int t,n,a[N],top,stk[N],L[N],R[N],lim,pfx; long long ans;
#define lowbit(x) (x&-x)
class Tree_Array1
{
private:
long long bit[N<<1];
public:
inline void add(int x,CI y)
{
for (;x<=lim;x+=lowbit(x)) bit[x]+=y;
}
inline int get(int x,int ret=0)
{
for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
}
}T1;
class Tree_Array2
{
private:
long long bit[N<<1];
public:
inline void add(int x,CI y)
{
for (;x;x-=lowbit(x)) bit[x]+=y;
}
inline int get(int x,int ret=0)
{
for (;x<=lim;x+=lowbit(x)) ret+=bit[x]; return ret;
}
}T2;
#undef lowbit
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; for (scanf("%d",&n),lim=ans=0,i=1;i<=n;++i)
scanf("%d",&a[i]),lim=max(lim,a[i]);
for (top=0,i=1;i<=n;++i)
{
while (top&&a[i]<a[stk[top]]) --top;
if (!top) L[i]=1; else L[i]=stk[top]+1; stk[++top]=i;
}
for (top=0,i=n;i;--i)
{
while (top&&a[i]<=a[stk[top]]) --top;
if (!top) R[i]=n; else R[i]=stk[top]-1; stk[++top]=i;
}
for (i=1;i<=n;++i)
{
for (pfx=0,j=i;j>=L[i];--j)
if (pfx=max(pfx,a[j]),T1.add(pfx,1),pfx%a[i]==0) T2.add(pfx,1);
for (pfx=0,j=i;j<=R[i];++j)
if (pfx=max(pfx,a[j]),ans+=T2.get(pfx+1),pfx%a[i]==0) ans+=T1.get(pfx);
for (pfx=0,j=i;j>=L[i];--j)
if (pfx=max(pfx,a[j]),T1.add(pfx,-1),pfx%a[i]==0) T2.add(pfx,-1);
}
printf("%lld\n",ans);
}
return 0;
}
标签:const,int,Codeforces,RI,pfx,Div,include,Round,define
From: https://www.cnblogs.com/cjjsb/p/16732893.html