2018.10.9模拟考试

看题请戳我!

T1 一道很水的贪心。(然而蒟蒻博主一如既往地没A)

维护一个小根堆,考虑在每次插入元素时:

1.若新元素比堆顶小,说明在此时买入必然比在堆顶时买入更优,因此把新元素直接插入堆中。

2.若新元素比堆顶大,说明在此时卖出必然能获得收益,因此将收益累计入答案中,再把堆顶删除。

     同时还要把新元素两次插入堆中。

原因:在最优解中,此元素可能并非作为“卖出”的一部分,而是作为“未进行操作”的一部分。插

入一次可以使此元素从“卖出”状态反悔到“未进行操作”状态。同样,再次插入可以使此元

素从“未进行操作”状态反悔到“买入”状态,从而保证了所有情况均被考虑。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL双端队列容器
#include<list>//STL线性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL队列容器
#include<set>//STL集合容器
#include<stack>//STL堆栈容器
#include<utility>//STL通用模板类
#include<vector>//STL动态数组容器
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
ll n,ans;
priority_queue<ll,vector<ll>,greater<ll> > que;
signed main()
{
    freopen("trade.in","r",stdin);
    freopen("trade.out","w",stdout);
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        ll u;scanf("%lld",&u);
        if(que.empty()) que.push(u);
        else if(u<que.top()) que.push(u);
        else ans+=u-que.top(),que.pop(),que.push(u),que.push(u);
    }printf("%lld\n",ans);
    return 0;
}


T2 一道第一眼看不出正确算法的题。

看一眼数据范围,n<=10^5。显然O(nlogn)(吗?)

推一推式子,发现并没有O(nlogn)的式子出现。

emmm...算了,还是打部分分吧。

看一眼部分分,嗯,前4个点暴力O(n^2)就能水过去。

等下...这中间6个点是怎么回事?n全部相等?m全部相等?

瞬间茅塞顿开——莫队。

这告诉我们要多关心部分分中的条件,也许正解就藏在其中。

没什么好说的,计算式也很好推,唯一要注意的就是要把所有除法替换成乘逆元。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL双端队列容器
#include<list>//STL线性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL队列容器
#include<set>//STL集合容器
#include<stack>//STL堆栈容器
#include<utility>//STL通用模板类
#include<vector>//STL动态数组容器
#define INF 0x3f3f3f3f
#define ll long long
#define MOD 1000000007
using namespace std;
ll T,Q,N,M,siz,fac[100001],inv[100001],blk[100001],ans[100001];
struct uio{
    ll n,m,id;
}qry[100001];
ll qpow(ll x,ll y)
{
    ll tmp=1;while(y)
    {if(y&1) (tmp*=x)%=MOD;
    (x*=x)%=MOD,y/=2;}
    return tmp;
}
ll C(int x,int y)
{
    if(x<y) return 0;
    return fac[x]*inv[y]%MOD*inv[x-y]%MOD;
}
bool cmp(uio x,uio y) {return (blk[x.n]==blk[y.n]? x.m<y.m:blk[x.n]<blk[y.n]);}
void Init()
{
    fac[0]=1;
    for(ll i=1;i<=N;i++) fac[i]=fac[i-1]*i%MOD;
    inv[N]=qpow(fac[N],MOD-2);
    for(ll i=N-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%MOD;
    siz=sqrt(N);
    for(ll i=1;i<=N;i++) blk[i]=(i-1)/siz+1;
    sort(qry+1,qry+1+Q,cmp);
}
signed main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    scanf("%lld%lld",&T,&Q);
    for(ll i=1;i<=Q;i++)
        scanf("%lld%lld",&qry[i].n,&qry[i].m),
        qry[i].id=i,N=max(N,qry[i].n),M=max(M,qry[i].m);
    Init();
    ll n=1,m=-1,tmp=0;
    for(ll i=1;i<=Q;i++)
    {
        while(n<qry[i].n) ((tmp*=2)-=C(n,m)-MOD)%=MOD,n++;
        while(m<qry[i].m) m++,(tmp+=C(n,m))%=MOD;
        while(m>qry[i].m) (tmp-=C(n,m)-MOD)%=MOD,m--;
        while(n>qry[i].n) n--,((tmp+=C(n,m))*=inv[2])%=MOD;
        //嗯对博客最后一句说的就是它------------^^^^^^^^------------
        ans[qry[i].id]=tmp;
    }
    for(ll i=1;i<=Q;i++) printf("%lld\n",ans[i]);
    return 0;
}


T3 一道丧心病狂的题目...

对于第一种查询,只需求出每行楼盘个数的前缀和即可。可以开2个sum数组分别表示"行前缀和"和"列差分"。

对于第二种查询,用并查集维护。可以开n个行vector和m个列vector,在插入完成后对每个vector统计。

具体操作步骤请查看代码注释。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL双端队列容器
#include<list>//STL线性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL队列容器
#include<set>//STL集合容器
#include<stack>//STL堆栈容器
#include<utility>//STL通用模板类
#include<vector>//STL动态数组容器
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
typedef pair<int,int> pr;
int ID,n,m,k,q,sum1[100002],sum2[100002];
int lnsum=0,mgsum,fa[100002];
int ans1[100002],ans2[100002];
struct uio{
    int lx,ly,rx,ry;
}prg[100002];
struct oiu{
    int id,l,r;
    friend bool operator < (const oiu &x,const oiu &y)
    {return (x.l==y.l? x.r<y.r:x.l<y.l);}
};
vector<oiu> row[100002],col[100002];
vector<pr> dsu[100002];
int find(int x) {return (x==fa[x]? x:fa[x]=find(fa[x]));}
void merge(int x,int y)
{
    int xx=find(x),yy=find(y);
    if(xx!=yy) fa[xx]=yy,mgsum++;
}
int main()
{
    freopen("building.in","r",stdin);
    freopen("building.out","w",stdout);
    scanf("%d%d%d%d%d",&ID,&n,&m,&k,&q);
    for(int i=1;i<=k;i++)
    {
        int lx,ly,rx,ry;
        scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
        prg[i]={lx,ly,rx,ry};
        oiu lenx={i,lx,rx},leny={i,ly,ry};
        row[lx].push_back(leny);
        col[ly].push_back(lenx);
        if(lx==rx) sum1[lx]+=(ry-ly+1);//行数量
        else sum2[lx]++,sum2[rx+1]--;//列差分
    }
    for(int i=1;i<=n;i++) sort(row[i].begin(),row[i].end());
    for(int i=1;i<=m;i++) sort(col[i].begin(),col[i].end());
    for(int i=1;i<=k;i++)
    {
        int dwn=prg[i].rx+1;//第i条的下面一行
        if(dwn<=n&&row[dwn].size())//第i条的下面一行作为某些条的上边界
        {
            oiu range={0,prg[i].ry,m+1};//第i条的右边
            int tmp=upper_bound(row[dwn].begin(),row[dwn].end(),range)
                    -row[dwn].begin()-1;//l<=ry的第一条
            for(;tmp>=0&&row[dwn][tmp].r>=prg[i].ly;tmp--)//r>=ly
                dsu[dwn].push_back(make_pair(i,row[dwn][tmp].id));//在dwn行连接
        }
        int rgt=prg[i].ry+1;//第i条的右边一列
        if(rgt<=m&&col[rgt].size())//第i条的右边一列作为某些条的左边界
        {
            oiu range={0,prg[i].rx,n+1};//第i条的下面
            int tmp=upper_bound(col[rgt].begin(),col[rgt].end(),range)
                    -col[rgt].begin()-1;//l<=rx的第一条
            for(;tmp>=0&&col[rgt][tmp].r>=prg[i].lx;tmp--)//r>=lx
                dsu[max(prg[i].lx,prg[col[rgt][tmp].id].lx)].push_back(make_pair(i,col[rgt][tmp].id));
                //在 第i条的上边界 与 该条的上边界 的靠下者 连接
        }
    }
    for(int i=1;i<=n;i++) sum2[i]+=sum2[i-1];//差分->数量
    for(int i=1;i<=n;i++) sum2[i]+=sum2[i-1],//数量->前缀和
                          sum1[i]+=sum1[i-1],//数量->前缀和
                          ans1[i]=sum1[i]+sum2[i];//第一种查询
    for(int i=1;i<=k;i++) fa[i]=i;
    for(int i=1;i<=n;i++)
    {
        lnsum+=row[i].size();//第i行作为上边界的条的个数
        for(int j=0;j<dsu[i].size();j++)
            merge(dsu[i][j].first,dsu[i][j].second);//在第i行合并的两条
        ans2[i]=lnsum-mgsum;//总条数减去合并次数
    }
    for(int i=1;i<=q;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        if(!u) printf("%d\n",ans1[v]);
        else printf("%d\n",ans2[v]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/water-radish/p/9761254.html

时间: 2024-11-10 15:31:10

2018.10.9模拟考试的相关文章

2018.10.6模拟考试

感动...某毒瘤出题人这次出的题竟然可做... 看题目请戳我! T1 这题乍一看就知道是一道数学公式题...自己仔细推推就能推出来... 已知(x+1)^n=C(n,0)*  x  ^n+C(n,1)*  x  ^(n-1)+...+C(n,n)*  x  ^0 易知(x+2)^n=C(n,0)*(x+1)^n+C(n,1)*(x+1)^(n-1)+...+C(n,n)*(x+1)^0 所以可以分别维护sum[x^0]~sum[x^k],插入时按照(x-1)插入,修改时将sum从x^n到x^0分

2018.7.23模拟考试

今天我居然A了一道题???怕不是把明年的运气都用光了 T1 题意简述:给出两个n*n的矩阵,m次询问它们的积中给定子矩阵的数值和. n<=2000,m<=50000 解题思路:这道题其实最主要的是这个...每个测试点时限6秒 这告诉我们...暴力就能过... 当然也不能随便暴力.二维前缀和即可.复杂度O(nm). #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib

2018.6.19 Java模拟考试(基础习题)

Java模拟考试(基础习题) 一.单选题(每题1分 * 50 = 50分) 1.java程序的执行过程中用到一套JDK工具,其中javac.exe指( B ) A.java语言解释器 B.java字节码编译器 C.java文档生成器 D.java类分解器 2.在Java语言中,不允许使用指针体现出的Java特性是( D ) A.可移植 B.解释执行 C.健壮性 D.安全性 3. 00101010(&)00010111语句的执行结果是( C ) A.11111111 B.00111111 C.00

阿里云云计算认证ACP模拟考试练习题第6套模拟题分享(共10套)

阿里云认证考试包含ACA.ACP.ACE三种认证类型,报名考试最多的是ACP认证考试,本人整理了100道全真阿里云ACP认证考试模拟试题,适合需要参加阿里云ACP认证考试的人复习,模拟练习.此为第6套模拟题分享. 阿里云云计算认证ACP模拟考试练习题6 认证级别 云计算 大数据 云安全 中间件 助理工程师(ACA) 云计算助理工程师认证报名入口 大数据助理工程师认证报名入口 云安全助理工程师认证报名入口 专业工程师(ACP) 云计算工程师认证报名入口 大数据工程师认证报名入口 大数据分析师认证报

驾照理论模拟考试系统Android源码下载

???驾照理论模拟考试系统Android源码下载 <ignore_js_op> 9.png (55.77 KB, 下载次数: 0) <ignore_js_op> 10.png (27.64 KB, 下载次数: 0) 详细说明:http://android.662p.com/thread-302-1-1.html 驾照理论模拟考试系统Android源码下载,布布扣,bubuko.com

模拟考试题目分享

1.多米诺骨牌(domino.pas) Jzabc对多米诺骨牌有很大的兴趣,然而他的骨牌比较特别,只有黑色的和白色的两种.他觉得如果存在连续三个骨牌是同一种颜色,那么这个骨牌排列便不是美观的.现在他有n个骨牌要来排列,他想知道不美观的排列个数.由于数字较大,数学不好的他又不会统计,所以他请你来帮忙.希望你在一秒内求出不美观的排列个数. [输入] 只有一个正整数,即要排列的骨牌个数. [输出] 一个数,即不美观的排列个数. [样例输入] 4 [样例输出] 6 [样例解释] 有四种不美观的排列. 黑

RHCE模拟考试

真实考试环境说明: 你考试所用的真实物理机器会使用普通账号自动登陆,登陆后,桌面会有两个虚拟主机图标,分别是system1和system2.所有的考试操作都是在system1和system2上完成.System1充当服务端,system2充当客户端.这些虚拟机的系统登陆密码请留意当时的考试细则说明. 模拟考试环境说明: 您有三台虚拟机,分别是classroom-rh254,server-rh254,desktop-rh254.三台虚拟主机的网络和主机名已经配置好,均位于example.com(1

全新雅思模拟考试开启全国高校预热活动

2015年12月12日, CMI雅思模拟考试管理中心(www.my-ielts.org )举行了首场全新雅思模拟考试高校预热活动,本次活动共有来自清华大学.北京大学.中央民族大学.中央财经大学.北京航空航天大学.北京中医药大学.北京体育大学.北京工业大学.吉林大学.西南大学.山东大学.天津大学.武汉大学.南京大学.兰州大学.首都师范大学.广东外语外贸大学.北方工业大学.成都理工大学.西北民族大学等20多所高校的逾500名考生报名参加.本次考试采用在线考试的形式,由考生在学校机房.宿舍.家中等不同

赣南师范学院数学竞赛培训第10套模拟试卷参考解答

1. 设 $f,g$ 是某数域上的多项式, $m(x)$ 是它们的首一最小公倍式, 而 $\scrA$ 为该数域上某线性空间 $V$ 的一个线性变换. 试证: $$\bex \ker f(\scrA)+\ker g(\scrA)=\ker m(\scrA). \eex$$ 证明: 先证: $\ker f(\sigma)+\ker g(\sigma)\subset\ker m(\sigma).$ 由 $f|m$, $g|m$ 知 $\ker f(\sigma)\subset \ker m(\sig