IvanZhang2009
2024-09-20 13:47:57
初赛。来早了点,开雀,吃二。
天一的老同学啊!唠嗑。
进场。秒了第一页的题。没有困难的 linux 题,不慌了!接着看,哈希,不会,最小割计数,这是平面图!快排,前几天刚做过一道快排;后面不看了。
秒了所有选择题。哈希猜了个
阅读做的很顺。计算量好大。
完型怎么又是万恶的 Um_nik
大法。手玩了一下,发现这个二分可以简单地理解为线段树二分!那就对完了,怎么
然后一眼看到了 0x?f
。这不会啊,跳。做完了别的,这题猜一个 0xff
。抄答题卡。
又做到这个题了,发现 update
里的东西我理解错了,改!然后手算 inf
的二进制形式,发现是 00011111000111110001111100011111
,那就是 0x1f
。这里花了十几分钟啊!
出场估满分。结果再一想发现 upper_bound()
可以找不到,那
97,符合预期。
快进到进考场。
13:57
:电脑屏幕好暗,尝试在设置里找亮度,突然听到“不要动电脑,两点开始试机”的指令,吓了一跳。
14:05
:写完了板子和快读,写了个快速幂学习编译命令。然后睡了二十分钟。
14:30
:花五分钟读了一下题,大致体感如下:t1 看上去比较水,要不然二分一下就好了;t2 看都不想看;t3 似乎不太难,有个显然的 dp 待会儿想想优化;t4 是什么一坨玩意儿。怎么要对每个前缀求答案。怎么多测
14:35
:胡 t1。写了这个:先排序,然后被删掉的肯定是一个前缀,我们枚举前缀长度,找到用哪个点来删它即可。14:42
通过了样例,时间复杂度
void Main(){
cin>>n;
REP(i,0,n)cin>>a[i];
sort(a,a+n);
int ans=n,x=0;
REP(i,0,n){
x=max(x,i+1);
while(x<n&&a[x]<=a[i])++x;
if(x>=n)break;
++x;--ans;
}
cout<<ans<<endl;
}
14:42
:手刃加速度公式。发现超速是一段区间,先写第一问。讨论了 delta 的正负性,推了除法的上下取整,对着很强的样例
while(n--){
int pos,v,delta;
cin>>pos>>v>>delta;
if(delta==0){
if(v>V)a.pb({pos,L});
}else if(delta>0){
if(v>V)a.pb({pos,L});
else{
int t=pos+(V*V-v*v)/(2*delta)+1;
if(t<=L)a.pb({t,L});
}
}else{
if(v>V){
delta=-delta;
int R=min(L,v*v/(2*delta)+pos);
R=min(R,pos+(v*v-V*V+2*delta-1)/(2*delta)-1);
if(pos<=R)a.pb({pos,R});
}
}
}
??:??
:写第二问。考虑一个 dp,15:19
通过,时间复杂度 upper_bound
。
sort(all(a));
n=q;vector<int>b(n);
REP(i,0,n)cin>>b[i];
int x=0;vector<pii>c;
for(auto [i,j]:a){
while(x<n&&b[x]<i)++x;
if(x<n&&b[x]<=j){
c.pb({x,upper_bound(all(b),j)-b.begin()-1});
}
}
++n;
vector<int>dp(n,0),lmn(n),mx(n,-1);
for(auto [i,j]:c)mx[j+1]=max(mx[j+1],i);
int cmx=-1,r=-1,mid=0,rmn=n;
REP(i,0,n){
cmx=max(cmx,mx[i]);
if(cmx==-1){
dp[i]=1;
continue;
}
while(r<i-1)rmn=min(rmn,dp[++r]);//[l,mid)[mid,r]
if(cmx>=mid){
mid=r;lmn[mid]=n;rmn=dp[mid];
for(int j=mid-1;j>=cmx;--j){
lmn[j]=min(lmn[j+1],dp[j]);
}
}
dp[i]=min(lmn[cmx],rmn)+1;
}
cout<<c.size()<<' '<<n-dp[n-1]<<endl;
15:20
胡 t3。考虑我们 P353 的 dp 优化:设
15:25
写完,一遍过了样例
15:30
考虑优化。我们先找 g++ 1.cpp -o -O2
。发现了之后一遍过了样例,跑得很快,时间 15:44
。
int n;
int a[200005],f[200005],g[1000005],p[200005];
void Main() {
cin>>n;
REP(i,0,n)cin>>a[i];
p[0]=0;
REP(i,1,n)p[i]=p[i-1]+(a[i]==a[i-1]? a[i]:0);
f[1]=0;
REP(i,2,n)f[i]=f[i-1]+(a[i-1]==a[i-2]? a[i-1]:0);
REP(i,0,n)g[a[i]]=-1e18;
int mx=-1e18;
REP(i,2,n){
f[i]=max(f[i],f[i-1]+(a[i]==a[i-2]? a[i-2]:0));
mx=max(mx,f[i-2]-p[i-2]);
f[i]=max(f[i],mx+p[i-1]);
if(i>2)g[a[i-3]]=max(g[a[i-3]],f[i-2]-p[i-2]);
f[i]=max(f[i],g[a[i]]+p[i-1]+a[i]);
}
int ans=f[n-1],s=0;
for(int i=n-2;i;--i){
s+=a[i]==a[i+1]? a[i]:0;
ans=max(ans,f[i]+s);
}
cout<<max(ans,s+(a[0]==a[1]? a[0]:0))<<endl;
}
16:10
一直到这会儿都在随机思考 t4,想不到任何 16:41
通过了所有样例。小插曲:样例
17:10
在此之前,都在随机思考啊,想到了若干种 set
维护,因为这样没啥细节,时间复杂度 17:57
,
#include<bits/stdc++.h>
#define ll long long
#define REP(i,a,n) for(int i=(a);i<(int)(n);++i)
#define pb push_back
#define pii pair<int,int>
using namespace std;
int n,q,k;
int a[200005],A[200005],qr[200005];
bool D[20][200005];
int op[400005],b[400005];
void build(int l,int r,int d,int p){
b[p]=D[d][l>>d];
if(l==r){
op[p]=l;
return;
}
int m=(l+r)>>1;
build(l,m,d-1,p*2+1);build(m+1,r,d-1,p*2+2);
int x=op[p*2+1],y=op[p*2+2];
if(x==-2||y==-2)op[p]=-2;
else if(x==-1&&y==-1)op[p]=-1;
else if(x>=0&&y>=0){
if(b[p])op[p]=a[y]>=d? y:x;
else op[p]=a[x]>=d? x:y;
}else op[p]=-2;
}
struct winners{
set<pii>a;
int b;ll s;
void init(){
a.clear();b=s=0;
}
void add(int l,int r){
b+=r-l+1;s+=1ll*(r-l+1)*(l+r+2)/2;
}
void Add(int x){a.insert({::a[x],x});}
void cl(int d){
while(a.size()&&a.begin()->first<d)a.erase(a.begin());
}
bool check(int d){
return b==0&&a.begin()->first>=d;
}
ll calc(){
ll res=s;
for(auto i:a)res+=i.second+1;
return res;
}
}res;
void solve(int l,int r,int d,int p,int N){
if(r<=N){
res.init();
res.Add(op[p]);
return;
}
if(l>N){
res.init();
res.add(l,r);
return;
}
int m=(l+r)>>1;
if(m==N){
res.init();
if(b[p]){
res.add(m+1,r);
res.Add(op[p*2+1]);
}else if(a[op[p*2+1]]>=d)res.Add(op[p*2+1]);
else res.add(m+1,r);
return;
}
if(N<m){
solve(l,m,d-1,p*2+1,N);
if(b[p])res.add(m+1,r);
else{
if(res.check(d))return;
res.cl(d);
res.add(m+1,r);
}
}else{
solve(m+1,r,d-1,p*2+2,N);
if(!b[p]){
if(a[op[p*2+1]]>=d)res.init(),res.Add(op[p*2+1]);
}else{
if(res.check(d))return;
res.cl(d);
res.Add(op[p*2+1]);
}
}
}
void Main(){
int r[4];
REP(i,0,4)cin>>r[i];
REP(i,0,n)a[i]=min(A[i]^r[(i+1)%4],k);
build(0,(1<<k)-1,k,0);
ll ans=0;
REP(_,0,q){
int x=qr[_],p=0,d=k;
if(!x){
ans^=_+1;
continue;
}
while(x<(1<<(d-1)))--d,p=p*2+1;
solve(0,(1<<d)-1,d,p,x);
ans^=1ll*(_+1)*res.calc();
}
cout<<ans<<endl;
}
signed main(){
cin>>n>>q;
REP(i,0,n)cin>>A[i];
REP(i,0,q)cin>>qr[i],--qr[i];
k=1;while((1<<k)<n)++k;
REP(i,1,k+1){
string s;cin>>s;
REP(j,0,(1<<(k-i))){
D[i][j]=s[j]=='1';
}
}
int tc;
cin>>tc;q=1;
while(tc--)Main();
return 0;
}
18:00
测试了一下,
18:31
左右两位高人开始高谈阔论。
- 你 AK 了吗?
- 没有啊,你 AK 了吗?
- 没有没有。zhk 肯定 AK 了。
- (此时我害怕极了)
- 我 t2 写了 5K!
- (此时我害怕极了,因为没听见是哪题,以为过了 t4)
- 5K 得了二三十分吧。
- (???)
- t2 不是板子题吗?先二分端点,然后线段覆盖,就解决了啊!
- 我 t4 胡乱写了点东西,不知道多少分啊。
- t3 呢?我一点也不会啊
- 我 t3 瞎写了个 dp 式子。竟然过样例了!
O(n^2) 的!都不知道为什么是对的!来我给你看看。- (这么菜?)
- 这次考线段树了吗?
- 没有吧。
- 我觉得 noip 会考线段树!
- noip 不会考线段树板子吧,就算考也只会考一个很难的题,然后需要用到线段树。所以会线段树也没什么用。除非他出线段树板子题。
- 唉,大佬啊,我还不会打线段树。
- ……(懒得听了)
回家路上发现大家 t1 怎么都是 dilworth 变成众数出现次数。我是不是假了???宣传 t3 线性做法,怒喷 t4 出题人。
自测
11:00
:怎么查分变今天了。
13:00
:怎么没有。怎么变 16:00
了。
16:00
:怎么没有。怎么变 17:30
了。
17:27
:怎么就有了?还是