NOIP模拟题qu ming zi[贪心][模拟][递归]

8 篇文章 0 订阅
5 篇文章 0 订阅

T1:
题意:给定操作及操作的数,对于某一种数据结构进行该操作,若为取出操作则判断操作取出的数与该数据结构该取出的数是否一致。
分析:同上,注意STL无自动判空,要加上判空。

#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
stack<int>p1;
queue<int>p2;
int p3[1000+5],cnt,pd[5],n,opt,v;
int main()
{

    freopen("qu.in","r",stdin);
    freopen("qu.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&opt,&v);
        if(opt==1){
            if(!pd[1])p1.push(v);
            if(!pd[2])p2.push(v);
            if(!pd[3])p3[++cnt]=v;
        }
        else{
            if(!pd[1]&&!p1.empty()){
                int tmp=p1.top();p1.pop();
                if(tmp!=v)pd[1]=1;
            }
            else pd[1]=1;
            if(!pd[2]&&!p2.empty()){
                int tmp=p2.front();p2.pop();
                if(tmp!=v)pd[2]=1;
            }
            else pd[2]=1;
            if(!pd[3]&&cnt>=0){
                sort(p3+1,p3+cnt+1);
                int tmp=p3[cnt--];
                if(tmp!=v)pd[3]=1;
            }
            else pd[3]=1;
        }
    }
    for(int i=1;i<=3;i++)if(pd[i])printf("No\n");
    else printf("YES\n");
    return 0;
}

T2:
题意:给定任务进行的时间和影响时间,这里对影响时间的定义是:若完成时间超过影响时间则所有超过的这段时间的任务超过值的最大为结果。从0开始求最小结果。
分析:可以直接用排序不等式,也可以确定最终完成的时间(然后就和之前的有一次的贪心一个套路。),也可以二分判断转决策为判断(然而我觉得会超时);

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,f,maxn;
struct buss
{
    int d,t;
}a[100000+5];
bool cmp(buss x,buss y)
{
    if(x.d<y.d)return true;
    return false;
}
int main()
{
    freopen("ming.in","r",stdin);
    freopen("ming.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d %d",&a[i].t,&a[i].d);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
    f+=a[i].t;
    maxn=max(maxn,f-a[i].d);
    }
    printf("%d",maxn);
    return 0;
}

T3:
题意:给定树的生成方式(具体为:在A树的C节点和B树的D节点连一条边,当然,A树和B树本身不变,只是COPY了一个来生成当前树而已),求该树上所有节点到编号比它大的节点的距离的和。
分析:这个只能看程序,公式比较麻烦,大概就是,A树和C树的答案,加上两树点数的积乘以连上的边的距离,加上各子树所有节点到被连节点的距离乘以另一棵子树的点数,最后的这个量要递归来求,考虑到最多递归60次,用MAP即使常数大也是完全没有问题的。
这里要注意几点,一个是,dis和len不是一个东西,在-g[a[cur]]时要特别注意这里的d[cur]需不需要减(比如dis里面就不需要减),以及dis里引用的len基本都乘以了g,但len里就不一定,这些都要靠清晰的逻辑,用变量时要时刻记住它们的意思。
最后,用了很多stl的程序不好调,要培养自己强大的静态差错能力(以及对于我这种咸鱼,还要敢去写去调);

#include<iostream>
#include<cstdio>
#include<map>
#define ll long long 
#define p(x,y) make_pair((x),(y))
using namespace std;
const ll modd=1e9+7;
map<ll,map<int,ll> >dis;
map<ll,map<pair<ll,ll>,ll> >len;
int a[65],b[65],n;
long long g[65],c[65],d[65],ans[65],l[65];
void getlen(int cur,ll x,ll r)
{
    if(!cur)return;
    if(x==r)return;
    if(x>r)swap(x,r);
    if(len[cur][p(x,r)])return;
    if(x+1>g[a[cur]]){
        getlen(b[cur],x-g[a[cur]],r-g[a[cur]]);
        len[cur][p(x,r)]=len[cur][p(r,x)]=len[b[cur]][p(x-g[a[cur]],r-g[a[cur]])]%modd;
    }
    else if(r<g[a[cur]]){
        getlen(a[cur],x,r);
        len[cur][p(x,r)]=len[cur][p(r,x)]=len[a[cur]][p(x,r)]%modd;
    }
    else {
        getlen(a[cur],x,c[cur]);
        getlen(b[cur],r-g[a[cur]],d[cur]);
        len[cur][p(x,r)]=len[cur][p(r,x)]=len[a[cur]][p(x,c[cur])]+
                         len[b[cur]][p(r-g[a[cur]],d[cur])]+l[cur];
        len[cur][p(x,r)]%=modd;
        len[cur][p(r,x)]%=modd;
    }
}
void getdis(int cur,ll y)
{
    if(!cur)return;
    if(dis[cur][y])return;
    int atmp=a[cur],btmp=b[cur];
    long long ctmp=c[cur],dtmp=d[cur],ytmp=y;
    if(y+1>g[atmp]){
        y-=g[atmp];
        swap(atmp,btmp);
        swap(ctmp,dtmp);
    }
    getdis(atmp,y);
    getdis(btmp,dtmp);
    getlen(atmp,y,ctmp);
    dis[cur][ytmp]=dis[atmp][y]+dis[btmp][dtmp]+len[atmp][p(y,ctmp)]*g[btmp]%modd+l[cur]*g[btmp]%modd;
    dis[cur][ytmp]%=modd;
}
void work(int u)
{
    scanf("%d %d %I64d %I64d %I64d",&a[u],&b[u],&c[u],&d[u],&l[u]);
    g[u]=g[a[u]]+g[b[u]];
    g[u]%=modd;
    ans[u]=ans[a[u]]+ans[b[u]]+g[a[u]]*g[b[u]]%modd*l[u]%modd;
    getdis(a[u],c[u]);
    getdis(b[u],d[u]);
    ans[u]+=dis[a[u]][c[u]]*g[b[u]]%modd+dis[b[u]][d[u]]*g[a[u]]%modd;
    ans[u]%=modd;
    printf("%I64d\n",ans[u]);
}
int main()
{
    freopen("zi.in","r",stdin);
    freopen("zi.out","w",stdout);
    scanf("%d",&n);g[0]=1;
    for(int i=1;i<=n;i++)work(i);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值