版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/82989521
2018.10.9模拟赛
T1 trade
正解:贪心
据说lyd讲过但并没有印象QAQ,考场上现推浪费了不少时间
其实就开个小根堆,每次把堆顶取出来看它是不是比当前的 小,如果小的话就把它替换成
然后再把 push进去
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 100005
#define LL long long
using namespace std;
int n,a[maxn];
LL ans;
priority_queue< pair<int,int> > q;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int main(){
freopen("trade.in","r",stdin);
freopen("trade.out","w",stdout);
n=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++){
if(!q.empty()){
int x=q.top().second;
if(a[x]<a[i]){
q.pop(); ans+=a[i]-a[x];
q.push(make_pair(-a[i],i));
}
}
q.push(make_pair(-a[i],i));
}
printf("%lld\n",ans);
return 0;
}
//5
//1 1 5 3 6
T2 sum
正解是莫队,但我不会莫队呜呜呜我果然是机房最菜的那个,然后就胡乱写了一堆暴力拿了60分
把询问离线然后分块,块外按n排序,快内按m排序
因为可以很容易地从 转移到 或者 所以只要维护两个指针转移就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 100005
#define LL long long
using namespace std;
int q,block;
LL fac[maxn],inv[maxn],ans[maxn];
const int mod=1e9+7,inv2=500000004;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct Query{
int n,m,id,pos;
bool operator <(const Query &x) const{
return pos==x.pos?m<x.m:pos<x.pos;
}
}a[maxn];
inline LL qpow(LL x,int k){
LL ret=1;
while(k){
if(k&1) (ret*=x)%=mod;
(x*=x)%=mod; k>>=1;
} return ret;
}
inline void prework(){
fac[0]=1; inv[1]=1;
for(int i=1;i<=100000;i++)
fac[i]=(fac[i-1]*i)%mod;
inv[100000]=qpow(fac[100000],mod-2);
for(int i=100000;i>=1;i--) inv[i-1]=(inv[i]*i)%mod;
}
inline LL C(int n,int m){
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void solve(){
sort(a+1,a+q+1);
int nn=0,nm=0; LL cur=1;
for(int i=1;i<=q;i++){
int x=a[i].n,y=a[i].m;
while(nn<x){
(cur*=2)%=mod; cur=(cur-C(nn,nm)+mod)%mod; nn++;
}
while(nm<y){
nm++;(cur+=C(nn,nm))%=mod;
}
while(nn>x){
nn--;cur=(cur+C(nn,nm))%mod; (cur*=inv2)%=mod;
}
while(nm>y){
cur=(cur-C(nn,nm)+mod)%mod; nm--;
}
ans[a[i].id]=cur;
}
for(int i=1;i<=q;i++)
printf("%lld\n",ans[i]);
}
int main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int t=rd(); q=rd(); block=sqrt(q);
for(int i=1;i<=q;i++){
a[i].n=rd(),a[i].m=rd(); a[i].id=i; a[i].pos=a[i].n/block;
}
prework(); solve();
return 0;
}
/*
1
5
1 1
2 1
3 2
4 3
5 5
*/
T3 building
本场最毒瘤的题了吧···不过部分分分的很清楚,打了40的暴力qwq
正解讲了两种:
第一种是xcc讲的,就是用各种 存横块和竖块的信息,当 的时候非常简单,只需要差分 前缀和就好了
但是当 的时候就有些麻烦了,首先可以用并查集维护连通性,顺便算出联通块个数,然后一行一行的扫
一边扫一边用维护,每次从上一行转移过来,这个可以用 里面存的信息办到
但是代码非常长并且细节很多,一定要脑子清醒的时候写
第二种是某大佬讲的,就是用扫描线处理这些信息,不过好像麻烦···
于是我就写了第一种:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define int long long
#define re register
#define N 200005
using namespace std;
int n,m,k,cntq,f[N],tot,ans[N],cnt,sum[N],c[N],rt=1;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct Node{
int l,r,id;
Node(){}
Node(const int x,const int y,const int z){
l=x,r=y,id=z;
}
}tmp[N];
inline bool cmpl(const Node &a,const Node &b){return a.l<b.l;}
inline bool cmp(const Node &a,const Node &b){return a.r<b.r;}//按r排序
vector<Node> line[N],row[N],stli[N],enli[N];
vector<int> q[2][N];
inline int find(int x){
return x==f[x]?x:(f[x]=find(f[x]));
}
inline void add(int x,int y){
x=find(x),y=find(y);
if(x==y) return;
--cnt; f[x]=y;
}
inline void solve(){
for(re int i=1;i<=tot;i++) f[i]=i;
for(re int i=1,t;i<=n;i++){
cnt+=stli[i].size()+row[i].size();//从1~i行的联通块
for(re int j=0;j<row[i].size();j++){//把上一行和它联通的都连上
t=lower_bound(row[i-1].begin(),row[i-1].end(),Node(0,row[i][j].l,0),cmp)-row[i-1].begin();
for(;t<row[i-1].size()&&row[i-1][t].l<=row[i][j].r;++t)
add(row[i][j].id,row[i-1][t].id);
int p=row[i][j].l-1;//和左边一列联通的连上
if(p>0){
t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
if(t<line[p].size()&&line[p][t].l<=i)
add(row[i][j].id,line[p][t].id);
}
p=row[i][j].r+1;//右边同理
if(p<=m){
t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
if(t<line[p].size()&&line[p][t].l<=i)
add(row[i][j].id,line[p][t].id);
}
}//处理列
for(re int j=0;j<stli[i].size();j++){//上面横着的
t=lower_bound(row[i-1].begin(),row[i-1].end(),Node(0,stli[i][j].l,0),cmp)-row[i-1].begin();
if(t<row[i-1].size()&&row[i-1][t].l<=stli[i][j].l&&row[i-1][t].r>=stli[i][j].l)
add(stli[i][j].id,row[i-1][t].id);
}
for(re int j=0;j<enli[i].size();j++){//下面横着的
t=lower_bound(row[i].begin(),row[i].end(),Node(0,enli[i][j].l,0),cmp)-row[i].begin();
if(t<row[i].size()&&row[i][t].l<=enli[i][j].l&&row[i][t].r>=enli[i][j].l)
add(row[i][t].id,enli[i][j].id);
}
for(re int j=0,t;j<stli[i].size();++j){
int p=stli[i][j].l-1;
if(p>0){//左边竖着的
t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
if(t<line[p].size()&&line[p][t].l<=i)
add(line[p][t].id,stli[i][j].id);
}
p=stli[i][j].l+1;
if(p<=m){//右边竖着的
t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
if(t<line[p].size()&&line[p][t].l<=i)
add(line[p][t].id,stli[i][j].id);
}
}
for(re int j=0;j<q[1][i].size();j++)
ans[q[1][i][j]]=cnt;
}
return;
}
signed main(){
freopen("building.in","r",stdin);
freopen("building.out","w",stdout);
int useless=rd();
n=rd(); m=rd(); k=rd(); cntq=rd();
for(re int i=1;i<=k;i++){
int x1=rd(),y1=rd(),x2=rd(),y2=rd();
if(x1==x2){
row[x1].push_back(Node(y1,y2,0));
sum[x1]+=y2-y1+1;
}
else line[y1].push_back(Node(x1,x2,0));
}
for(re int i=1;i<=cntq;i++){
int a=rd(),b=rd();
q[a][b].push_back(i);
}
for(re int i=1;i<=m;i++)//差分
for(re int j=0;j<line[i].size();j++)
++c[line[i][j].l],--c[line[i][j].r+1];
for(re int i=1;i<=n;i++) c[i]+=c[i-1];
for(re int i=1;i<=n;i++)
c[i]+=c[i-1],sum[i]+=sum[i-1];
for(re int i=1,t;i<=n;i++){
t=c[i]+sum[i];
for(re int j=0;j<q[0][i].size();j++)
ans[q[0][i][j]]=t;//求楼房个数
}
if(useless>=5 && useless<=8){
for(re int i=1;i<=cntq;i++)
printf("%lld\n",ans[i]);
return 0;
}
for(re int i=1;i<=n;i++)
if(row[i].size()){
sort(row[i].begin(),row[i].end(),cmpl);
int num=0;
for(re int j=0;j<row[i].size();j++)//先把一行里首尾相接的连起来
if(num&&tmp[num].r+1==row[i][j].l) tmp[num].r=row[i][j].r;
else tmp[++num]=row[i][j],tmp[num].id=++tot;
row[i].clear();
for(re int j=1;j<=num;j++) row[i].push_back(tmp[j]);
}
for(re int i=1;i<=m;i++)
if(line[i].size()){
sort(line[i].begin(),line[i].end(),cmpl);
int num=0;
for(re int j=0;j<line[i].size();j++)
if(num&&tmp[num].r+1==line[i][j].l) tmp[num].r=line[i][j].r;
else tmp[++num]=line[i][j],tmp[num].id=++tot;
line[i].clear();
for(re int j=1;j<=num;j++){
line[i].push_back(tmp[j]);//stli存的是第i行为开头的竖块信息
stli[tmp[j].l].push_back(Node(i,tmp[j].r,tmp[j].id));
if(tmp[j].r+1<=n)
enli[tmp[j].r+1].push_back(Node(i,tmp[j].l,tmp[j].id));
}//enli存的是第i-1行为结尾的竖块信息
}
solve();
for(re int i=1;i<=cntq;i++)
printf("%lld\n",ans[i]);
return 0;
}
总分 分
三校联考
本校
啊我们好菜啊