20201128 模拟赛总结
题目PDF,提取码 99bh
。
\(95+5+50+4=154\text{pts}\),rk3。
violet_holmes \(155\text{pts}\) rk2,差一分就离谱((
T1
模拟即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
bool a[110][110];
int main()
{
queue<char> que;
int hx=0,hy=0,tx=0,ty=0;
int n,m,t,q;
scanf("%d %d %d %d",&n,&m,&t,&q);
for(int i=1;i<=t;i++)
{
int x,y;
scanf("%d %d",&x,&y);
a[x][y]=1;
}
int stx,sty;
scanf("%d %d",&stx,&sty);
hx=stx;hy=sty;
a[hx][hy]=1; // 考试的时候没加这句话,挂了五分。。
int i;
for(i=1;i<=q;i++)
{
int pos;
scanf("%d",&pos);
if(pos==1)
{
char s[10];
scanf("%s",s);
if(s[0]=='R') hy++;
else if(s[0]=='L') hy--;
else if(s[0]=='U') hx--;
else if(s[0]=='D') hx++;
if(hx<1 || hx>n || hy<1 || hy>m) break;
if(a[hx][hy]) break;
a[hx][hy]=true;
que.push(s[0]);
}
else
{
if(tx==0 && ty==0)
{
tx=stx;ty=sty;
a[tx][ty]=0;
}
else
{
char c=que.front(); que.pop();
if(c=='R') ty++;
else if(c=='L') ty--;
else if(c=='U') tx--;
else if(c=='D') tx++;
a[tx][ty]=0;
}
}
}
printf("%d",i>q?-1:i);
return 0;
}
T2
原题:洛谷 P2123
推式子,详见这里。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=20000;
struct node
{
int a,b;
node() {}
}a[N+10];
bool cmp(node x,node y) {return min(x.a,y.b)==min(x.b,y.a)?x.a<y.a:min(x.a,y.b)<min(x.b,y.a);}
typedef long long ll;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&a[i].a,&a[i].b);
sort(a+1,a+n+1,cmp);
ll sum=0,c=0;
for(int i=1;i<=n;i++)
{
sum+=a[i].a;
c=max(sum,c)+a[i].b;
}
printf("%lld\n",c);
}
return 0;
}
T3
另 \(b_i\) 表示区间 \([i,n]\) 内比 \(a_i\) 小的数的个数,显然区间的逆序对个数就是 \(\sum_{i=1}^n b_i\)。根据题意,可以得到一个结论:若一个数 \(a_i\) 被取出(不论是如何被取出),\(b_i\) 都会变为 \(0\),不会对答案产生再产生贡献,然后我们就可以使用线段树去维护。
具体地,可以一开始算出区间逆序对个数 \(s=\sum_{i=1}^n b_i\),线段树维护 \(\{a_i\}\) 的区间最小值和最小值的下标,第 \(i\) 次操作操作取出区间 \([p_i,n]\) 的最小值 \(a_k\) 并将 \(a_k\) 设为极大值,同时 \(s\) 相对应地减去 \(b_k\),直到 \(a_k>a_{p_i}\) 为止。
代码实现有一些难度。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=5e5;
int a[N+10],d[N+10],b[N+10];
inline void read(int &x)
{
x=0; int f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
x*=f;
}
struct seg
{
int l,r,min,pos;
}t[N*4+10];
void push_up(int p)
{
if(t[p*2].min<t[p*2+1].min)
{
t[p].min=t[p*2].min;
t[p].pos=t[p*2].pos;
}
else
{
t[p].min=t[p*2+1].min;
t[p].pos=t[p*2+1].pos;
}
}
void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;
if(l==r)
{
t[p].min=a[l];
t[p].pos=l;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
push_up(p);
}
void modify(int p,int l,int d)
{
if(t[p].l==t[p].r)
{
t[p].min=d;
return;
}
int mid=(t[p].l+t[p].r)/2;
if(l<=mid) modify(p*2,l,d);
else modify(p*2+1,l,d);
push_up(p);
}
//first:value, second:position
pair<int,int> query(int p,int l,int r)
{
if(l<=t[p].l && t[p].r<=r) return make_pair(t[p].min,t[p].pos);
int mid=(t[p].l+t[p].r)/2;
pair<int,int> ans=make_pair(0x7fffffff,0x7fffffff);
if(l<=mid) ans=min(ans,query(p*2,l,r));
if(r>mid) ans=min(ans,query(p*2+1,l,r));
return ans;
}
int s;
int c[N+10];
void modify(int x,int d) {for(;x<=s;x+=x&-x) c[x]+=d;}
int query(int x)
{
int ans=0;
for(;x;x-=x&-x) ans+=c[x];
return ans;
}
typedef long long ll;
int main()
{
int n,m;
read(n);read(m);
for(int i=1;i<=n;i++)
{
read(a[i]);
d[i]=a[i];
}
sort(d+1,d+n+1);
s=unique(d+1,d+n+1)-d-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(d+1,d+s+1,a[i])-d;
ll ans=0;
for(int i=n;i;i--)
{
b[i]=query(a[i]-1);
ans+=b[i];
modify(a[i],1);
}
build(1,1,n);
for(int Case=1;Case<=m;Case++)
{
int p;
read(p);
while(1)
{
pair<int,int> tmp=query(1,p,n);
if(tmp.first>a[p]) break;
ans-=b[tmp.second];
modify(1,tmp.second,0x7fffffff);
}
printf("%lld\n",ans);
}
return 0;
}
/*
5 3
1 4 2 5 3
5 2 4
*/
T4
弃了。
如果 NOIP 考这题我大概率输出随机数走人。