评价
这次的题目好像没有什么好喷的,还是挺不错的。
那这次我们喷什么?喷键盘!
一场模拟赛我换了三个键盘,其中两个是好似板砖,另一个的空格就像在玩跷跷板。
为什么有按键那么硬的键盘!!!!/fn/fn
中间还有一次因为换键盘,电脑要重启,然后代码没了,呜呜呜。
题目本身还行,因为评测机太慢被卡掉 40 分,申诉之后调大了时限跑过去了。
后来发现洛谷评测机能 1s 1e9!又能多拿 40 分!
这是非常棒的。
T1 是找规律题,因为细节特判被卡了一个点,这是不好的。(还好不是多组数据)
T2 写了一个枚举右端点加二分套线段树的 (O(nlog^2 n)) 做法,期望 (80),被卡 (40),后来要回来了。
T3 只会一个 (O(n^3)) 加一个部分分特判做法,期望 (30),洛谷评测机跑的快,能拿到 (70)。
期望得分:(100+80+30=210pts)
实际得分:(90+40+30=160pts)
放大时限后得分:(90+80+30=200pts)
洛谷评测:(90+80+70=240pts)
补题通道:
T1 | T2 | T3 |
---|---|---|
( ext{U177562 lock}) | ( ext{U177563 sequence}) | ( ext{U177564 fight}) |
没有题解,没仔细研究std,所以只讲考场做法,不是正解!!。
代码只有 T1 是自己写的(我感觉我写的比 std好看),其他的是 std。
代码为啥使用了 Tab 字符啊,八空格有点恶心。
T1
找规律。
对于 (L),不管它是奇数还是偶数,都能通过倒两次水使它们的总和达到 (L+2)。
- 偶数:先往一个杯里倒 (frac{L}{2}+0.5) 滴水,再向另一个杯里倒 (frac{L}{2}+1.5) 滴水。
- 奇数:先往一个杯里倒 (leftlfloor frac{L}{2} ight floor +1) 滴水,再向另一个杯中到 (leftlfloor frac{L}{2} ight floor +2) 滴水。
然后两个杯子来回倒就可以,不难发现一次向一个杯子倒两滴是最快的,直到两杯水之和达到 (R) 或者 (R-1)。
所以答案为 (2+leftlfloor frac{R-L-2}{2} ight floor)。
当 (R le L+2) 和 (R le 2) 时的所有情况需要单独考虑。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#define LL long long
using namespace std;
const int MAXN = 1e5 + 10;
const int INF = 1e9 + 7;
const int mod = 1e9 + 7;
LL L, R;
LL read() {
LL s = 0, f = 0; char ch = getchar();
while(!isdigit(ch)) f = (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 3) + (s << 1) + ch - '0', ch = getchar();
return f ? -s : s;
}
int main() {
// freopen("lock.in","r",stdin);
// freopen("lock.out","w",stdout);
L = read(), R = read();
if(R == 1) { puts("0"); return 0; }
if(R <= L + 2) {
if(R <= 2) puts("1");
else puts("2");
} else {
cout << 2 + (R - L - 2) / 2 << "
";
}
return 0;
}
T2
std 貌似是个双指针。
固定右端点,二分左端点,然后用线段树求出把那一段区间赋为 (0) 最赚,对合法区间取长度最大值,时间复杂度 (O(n log^2 n))。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define mk make_pair
#define rint register int
using namespace std;
inline ll read(){ll w=1,s=0;char ch=getchar();while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}return w*s;}
ll Sum[2000010];
ll tmp[2000010];
ll Max[2000010],pos[2000100];
int A[2000010];
ll n,p,d;
int main()
{
// freopen("sequence.in","r",stdin);
// freopen("sequence.out","w",stdout);
n=read(),p=read(),d=read();
for(rint i=1;i<=n;++i)
{
A[i]=read();Sum[i]=Sum[i-1]+A[i];
}
for(rint i=1;i<=d-1;++i) tmp[i]=Sum[i];
for(rint i=d;i<=n;++i)
{
tmp[i]=Sum[i]-Sum[i-d];
}
// if(n<=d)
// {
// cout<<n<<"
";
// return 0;
// }
int rp=0;int head=1,tail=0;
int ans=min(d,n);
// cout<<rp<<"
";
for(rint l=1;l<=n;++l)
{
while(head<=tail&&pos[head]<l+d-1) head++;
while(rp<n)
{
if(rp-l+1<d)
{
rp++;
if(rp-l+1==d)
{
while(head<=tail&&tmp[rp]>Max[tail]) tail--;
Max[++tail]=tmp[rp];
pos[tail]=rp;
}
}
else
{ ll tt=-1e18;
if(head<=tail) tt=max(tt,Max[head]);
tt=max(tt,tmp[rp+1]);
if(Sum[rp+1]-Sum[l-1]-tt<=p)
{
rp++;
while(head<=tail&&tmp[rp]>Max[tail]) tail--;
Max[++tail]=tmp[rp];
pos[tail]=rp;
}
else break;
}
}
ans=max(ans,rp-l+1);
}cout<<ans;
return 0;
}
T3
std 写了个线段树????
(k=0) 的情况答案显然为 (0)。
考虑维护一个 (f_{a,b}) 表示 (a,b)两个点同时被多少线段覆盖。
枚举所有三元组 ((a,b,c)),显然合法情况只有两种,利用 (f) 数组判断是否合法即可。
时间复杂度 (O(n^3))。
洛谷评测跑的快把 (n=1000) 的部分卡过去了。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define mk make_pair
#define rint register int
//#define int ll
using namespace std;
inline int read(){int w=1,s=0;char ch=getchar();while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}return w*s;}
typedef pair<ll,ll> pa;
vector<pa> vec[200010];
int n,m;ll A[500010];
ll tot=0,q[500010];
ll Sum[500010],tag[500010],du[500100];
inline void pushdown(int now,int l,int r)
{
if(tag[now])
{ int mid=(l+r)>>1;
tag[now<<1]^=1;
tag[now<<1|1]^=1;
Sum[now<<1]=(mid-l+1)-Sum[now<<1];
Sum[now<<1|1]=(r-mid)-Sum[now<<1|1];
tag[now]=0;
}
}
inline void Modify(int now,int l,int r,int x,int y)
{
// cout<<now<<" "<<l<<" "<<r<<" "<<x<<" "<<y<<'
';
if(x<=l&&r<=y)
{
Sum[now]=(r-l+1)-Sum[now];
// cout<<Sum[now]<<"
";
tag[now]^=1;
return ;
}pushdown(now,l,r);
int mid=(l+r)>>1;
if(x<=mid) Modify(now<<1,l,mid,x,y);
if(y>mid) Modify(now<<1|1,mid+1,r,x,y);
Sum[now]=Sum[now<<1]+Sum[now<<1|1];
}
inline ll Query(int now,int l,int r,int x,int y)
{ if(x>y) return 0;
if(x<=l&&r<=y)
{
return Sum[now];
}pushdown(now,l,r);
int mid=(l+r)>>1;
ll res=0;
if(x<=mid) res=Query(now<<1,l,mid,x,y);
if(y>mid) res+=Query(now<<1|1,mid+1,r,x,y);
Sum[now]=Sum[now<<1]+Sum[now<<1|1];
return res;
}
inline void Solve()
{
for(rint i=1;i<=n;++i)
{
if(i!=1)
{
Modify(1,1,n,i-1,i-1);
}
int sz=vec[i].size();
for(rint j=0;j<sz;++j)
{
pa tmp=vec[i][j];
int l=tmp.first,r=tmp.second;
Modify(1,1,n,l,r);
}
du[i]=Query(1,1,n,1,i-1)+Query(1,1,n,i+1,n);
// cout<<du[i]<<"
";
}ll ans=1ll*n*(n-1)*(n-2)/6;
for(rint i=1;i<=n;++i)
{
ans-=1ll*(du[i]*(du[i]-1))/2;
}cout<<ans;
}
int main()
{
// freopen("fight.in","r",stdin);
// freopen("fight.out","w",stdout);
n=read();m=read();
for(rint i=1;i<=n;++i)
{
A[i]=read();
q[++tot]=A[i];
}sort(A+1,A+tot+1);
for(rint i=1;i<=m;++i)
{
int x=read(),y=read();
x=lower_bound(A+1,A+tot+1,x)-A;
y=upper_bound(A+1,A+tot+1,y)-A-1;
// cout<<x<<" "<<y<<"
";
if(x>=y) continue;
vec[x].pb(mk(x,y));
vec[y+1].pb(mk(x,y));
}
Solve();
return 0;
}