2019-2020 ICPC Northwestern European Regional Programming Contest (NWERC 2019) (A,E,H)
10.5 2019-2020 ICPC Northwestern European Regional Programming Contest (NWERC 2019)
我对不起cf
CFGI都不是我写的。
A.Average Rank(模拟)√
因为每次只会加一分,只会影响附近的人。
所以模拟一下就好了.. 注意维护个标记(好久前做的不想写了)。
#include <bits/stdc++.h>
#define gc() getchar()
typedef long long LL;
const int N=1e6+5;
int tag[N],las[N],sco[N];
LL ans[N],sum[N];
inline int read()
{
int now=0; char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
int main()
{
int n=read(),W=read();
for(int i=1; i<=W; ++i)
{
for(int k=read(); k--; )
{
int c=read(),s=sco[c]; ++sco[c];//LL
ans[c]+=sum[s]+1ll*tag[s]*(i-las[s]);
sum[s]+=1ll*tag[s]*(i-las[s]), ++tag[s], las[s]=i;
++s, ans[c]-=sum[s]+1ll*tag[s]*(i-las[s]);
sum[s]+=1ll*tag[s]*(i-las[s]), las[s]=i;
}
}
for(int i=1,s; i<=n; ++i) s=sco[i], ans[i]+=sum[s]+1ll*tag[s]*(W+1-las[s])+W;
for(int i=1; i<=n; ++i) printf("%.8f\n",1.0*ans[i]/W);
return 0;
}
E.Expeditious Cubing(精度)√
题很简单,但是 卡精度(绝了)。
读入时要将数乘100变为整数,不能读double再乘(迷之存储),写个Read()
或scanf("%d.%d",&x,&y)
。
输出两位小数时注意第一位小数可能要补0。
#include <bits/stdc++.h>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5;
inline int read()
{
int now=0,f=1; char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
inline int Read()
{
int now=0; char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
for(c=gc();isdigit(c);now=now*10+c-48,c=gc());
return now;
}
int main()
{
static int A[55];
for(int i=1; i<=4; ++i) A[i]=Read();//scanf("%d.%d",&x,&y);
std::sort(A+1,A+1+4);
int res=Read();
if(A[2]+A[3]+A[4]<=res*3) return puts("infinite"),0;
if(A[1]+A[2]+A[3]>res*3) return puts("impossible"),0;
int tmp=(3*res-A[2]-A[3])%100;
if(tmp<10) printf("%d.0%d\n",(3*res-A[2]-A[3])/100,(3*res-A[2]-A[3])%100);
else printf("%d.%d\n",(3*res-A[2]-A[3])/100,(3*res-A[2]-A[3])%100);
return 0;
}
/*
19.99
19.97
1.99
2.00
*/
H.Height Profile(线段树/树状数组)
\(Description\)
给定一条有\(n\)个上升或下降区域的折线(包含\(n+1\)个点)。
\(k\)次询问每次给定\(g\),设\(h[i]\)表示\(i\)处的高度,求最长的区间\([l,r]\)满足\(\frac{h[r]-h[l]}{r-l}\geq g\)(\(l,r\)为任意实数)。
\(n\leq 10^5, k\leq 50\)。
\(Solution\)
首先只考虑\(l,r\)取整数点的情况。
若\([l,r]\)满足条件,则有\(\frac{h[r]-h[l]}{r-l}\geq g\),即\(h[r]-gr\geq h[l]-gl\),令\(A[i]=h[i]-gi\),对每个点求最靠前的使得\(A[i]\geq A[j]\)的\(j\)即可。
如果\(l,r\)为实数,容易发现\([l,r]\)一定是恰好包含 只取整数点时答案最大的区间中的一个(否则区间可以延伸),且\(l,r\)至少有一个是整数(如果都是实数说明两边线段的斜率都很优,如果斜率相等则可以任取完整的一边,如果有一边更优则一定不需要取另一边)。
所以先 离散化+树状数组/线段树维护区间最小值 求出取整数点时的答案,再对所有可能的区间往左右两边延伸即可。
延伸的时候就是解方程:设此时由\(l\)向左多取\(p\)
由向右时同理。
(不知道二分为什么不对(WA on test 3)... 可二分的叭?)
读入忘了乘负号 改了一晚
线段树:
//218ms 3100KB(并不慢)
#include <bits/stdc++.h>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5,INF=1e9;
int h[N],tmp[N],A[N],Ref[N];
struct Segment_Tree
{
#define S N<<2
int mn[S];
#undef S
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,ls
#define rson m+1,r,rs
#define Update(rt) mn[rt]=std::min(mn[ls],mn[rs])
void Build(int l,int r,int rt)
{
if(l==r) {mn[rt]=A[l]; return;}
int m=l+r>>1;
Build(lson), Build(rson), Update(rt);
}
int Query(int l,int r,int rt,int v)
{
if(l==r) return l;
int m=l+r>>1;
if(mn[ls]<=v) return Query(lson,v);
return Query(rson,v);
}
}T;
inline int read()
{
int now=0,f=1; char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
inline int Read()
{
int now=0,f=1; char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
for(c=gc();isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
int main()
{
int n=read()+1,Q=read();
for(int i=1; i<=n; ++i) h[i]=read();
for(; Q--; )
{
int g=Read();
for(int i=1; i<=n; ++i) Ref[i]=A[i]=h[i]-g*i;
int ans=0; T.Build(1,n,1);
for(int i=1; i<=n; ++i)
ans=std::max(ans,i-(tmp[i]=T.Query(1,n,1,A[i])));
if(!ans) {puts("-1"); continue;}
double ans2=ans;
for(int r=1,l; r<=n; ++r)
if((l=tmp[r])>1 && r-l==ans && h[l-1]-h[l]+g!=0)//left
ans2=std::max(ans2,r-l+1.0*(A[r]-A[l])/(h[l-1]-h[l]+g));
for(int r=1,l; r<n; ++r)
if(r-(l=tmp[r])==ans && h[r]-h[r+1]+g!=0)//right
ans2=std::max(ans2,r-l+1.0*(A[r]-A[l])/(h[r]-h[r+1]+g));
printf("%.9f\n",ans2);
}
return 0;
}
树状数组:
//936ms 2000KB
#include <bits/stdc++.h>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5,INF=1e9;
int h[N],tmp[N],A[N],Ref[N];
struct BIT
{
int n,t[N];
#define lb(x) (x&-(x))
void Clear()
{
for(int i=1; i<=n; ++i) t[i]=INF;
}
void Modify(int p,int v)
{
for(; p<=n; p+=lb(p)) t[p]=std::min(t[p],v);
}
int Query(int p)
{
int res=INF;
for(; p; p^=lb(p)) res=std::min(t[p],res);
return res;
}
}T;
inline int read()
{
int now=0,f=1; char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
inline int Read()
{
int now=0,f=1; char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
for(c=gc();isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
int Find(LL v,int r)
{
int l=1,mid;
while(l<r)
if(Ref[mid=l+r>>1]<v) l=mid+1;
else r=mid;
return l;
}
int main()
{
int n=read()+1,Q=read();
for(int i=1; i<=n; ++i) h[i]=read();
for(; Q--; )
{
int g=Read();
for(int i=1; i<=n; ++i) Ref[i]=A[i]=h[i]-g*i;
std::sort(Ref+1,Ref+1+n);
int cnt=1;
for(int i=2; i<=n; ++i) if(Ref[i]!=Ref[i-1]) Ref[++cnt]=Ref[i];
for(int i=1; i<=n; ++i) A[i]=Find(A[i],cnt);
int ans=-1;
T.n=cnt, T.Clear();
for(int i=1; i<=n; ++i)
ans=std::max(ans,i-(tmp[i]=T.Query(A[i]))), T.Modify(A[i],i);
if(ans==-1) {puts("-1"); continue;}
double ans2=ans;
for(int r=1,l; r<=n; ++r)
if((l=tmp[r])>1 && r-l==ans && h[l-1]-h[l]+g!=0)//left
ans2=std::max(ans2,r-l+1.0*(Ref[A[r]]-Ref[A[l]])/(h[l-1]-h[l]+g));
for(int r=1,l; r<n; ++r)
if(r-(l=tmp[r])==ans && h[r]-h[r+1]+g!=0)//right
ans2=std::max(ans2,r-l+1.0*(Ref[A[r]]-Ref[A[l]])/(h[r]-h[r+1]+g));
printf("%.9f\n",ans2);
// for(int i=1,t; i<=n; ++i)
// if((t=tmp[i])>1 && i-t==ans)
// {
// double l=t-1,r=t,mid;
// while(l+eps<r)
// {
// mid=(l+r)*0.5;
// if(h[i]-h[t]+(h[t]-h[t-1])*(1-mid)>=g*(i-mid)) ans2=std::max(ans2,i-mid), r=mid;
// else l=mid;
// }
// }
// for(int i=1,t; i<n; ++i)
// if(i-(t=tmp[i])==ans)
// {
// double l=i,r=i+1,mid;
// while(l+eps<r)
// {
// mid=(l+r)*0.5;
// if(h[i]-h[t]+(h[i+1]-h[i])*mid>=g*(mid-t)) ans2=std::max(ans2,mid-t), l=mid;
// else r=mid;
// }
// }
}
return 0;
}
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------