zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",ans1[v]);
            else printf("%d
    ",ans2[v]);
        }
        return 0;
    }
  • 相关阅读:
    Multithread 之 synchronous
    【转】windows exe文件加载
    Transparent 之 SetLayeredWindowAttributes
    任意目录运行vs2005 tools
    【转】volatile
    Qt1命令行编译
    初识Qt
    typedef使用一
    Qthello
    源文件包含源文件
  • 原文地址:https://www.cnblogs.com/water-radish/p/9761254.html
Copyright © 2011-2022 走看看