NOIP2011题解

NOIP2011其实早就做完了。。。。一直懒得写。。。。

Day1

T1铺地毯

我什么都不想说,不会做您就没必要接着看了。。。。

#include<iostream>
using namespace std;
#define MAX 10001
int a[MAX],b[MAX],c[MAX],d[MAX],xx,yy,ans=-1,n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i)cin>>a[i]>>b[i]>>c[i]>>d[i];
    cin>>xx>>yy;
    for(int i=1;i<=n;++i)
        if(a[i]<=xx&&b[i]<=yy&&a[i]+c[i]>=xx&&b[i]+d[i]>=yy)ans=i;
    cout<<ans<<endl;
    return 0;
}

T2选择客栈

因为只有相同颜色才会产生贡献
记录一下上一个相同颜色的位置,以及当前是否有满足条件的咖啡店
用前缀和处理即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 210000
inline int read()
{
      register int x=0,t=1;
      register char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
      if(ch=='-'){t=-1;ch=getchar();}
      while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
      return x*t;
}
int N,K,P,tot,lt,sum[MAX],last[MAX],ans,pos[MAX];
int main()
{
    N=read();K=read();P=read();
    for(int i=1;i<=N;++i)
    {
        int c=read(),v=read();
        if(v<=P)lt=i;
        if(pos[c]<=lt)last[c]=sum[c];
        ans+=last[c];sum[c]++;pos[c]=i;
    }
    printf("%d\n",ans);
}   

T3Mayan游戏

大火题。。。。
其实就是暴力搜索 。。。。
题目要什么你就做什么。。。。
稍微剪下枝,相同颜色不用交换,如果是交换两个方块,就只要考虑往一侧交换就行了。。。。
稍微注意一下搜索顺序
(我的程序之前写的,,,不知道有什么鬼问题,用了一个特判。。。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
struct Step
{
    int x,y;
    int tow;
};
vector<Step> St;

int g[6][8],n,a,top[6];
bool Clear=false;

inline bool Fall();//掉落 
inline bool Del();//消除 
inline bool Blank();//图空 
inline bool Count();//合法判断
inline bool Special_Judge();//打表... 

inline void DFS(int st)
{
      if(st==n)
      {
          if(Blank())//消除完 
          {
              Clear=true;
              for(int i=0;i<St.size();++i)
                     cout<<St[i].x-1<<' '<<St[i].y-1<<' '<<St[i].tow<<endl;
              exit(0);
          }
          return;
      }
      if(st>=n)
          return;
      short int cop[6][8];
      short int Top[6];
      for(short int i=1;i<=5;++i)
          for(short int j=1;j<=7;++j)
              cop[i][j]=g[i][j];
      for(short int i=1;i<=5;++i)
          Top[i]=top[i];
      for(short int i=1;i<=4;++i)//枚举第i行向右的交换 
      {
          for(short int j=1;j<=top[i];++j)
          {
              if(g[i][j]==g[i+1][j])//如果两个交换的相等则没有交换的意义 
                  continue;
              swap(g[i][j],g[i+1][j]);
              St.push_back((Step){i,j,1});//记录向右移动 
              Del();
              DFS(st+1);
              for(short int x=1;x<=5;++x)//恢复原图 
                  for(short int y=1;y<=7;++y)
                      g[x][y]=cop[x][y];
              Fall();
              St.pop_back();
          }
      }
      for(short int i=2;i<=5;++i)
      {
          for(short int j=1;j<=top[i];++j)
          {
              if(g[i-1][j]==0)//向左交换如果不存在掉落则必定是向右交换的一种情况 
              {
                  swap(g[i][j],g[i-1][j]);
                  St.push_back((Step){i,j,-1});//记录向左移动 
                  Del();
                  DFS(st+1);
                  for(short int x=1;x<=5;++x)//恢复原图 
                      for(short int y=1;y<=7;++y)
                          g[x][y]=cop[x][y];
                  for(short int x=1;x<=5;++x)
                      top[x]=Top[x];
                  St.pop_back();
              }
          }
      }
}
int main()
{
    cin>>n;
    memset(g,0,sizeof(g));
    for(short int i=1;i<=5;++i)
        while(cin>>a)
        {
            if(a==0)break;
            top[i]+=1;
            g[i][top[i]]=a;
        }
    if(Special_Judge())
        return 0;
    DFS(0);
    if(!Clear)
        cout<<-1<<endl;
    return 0;      
}

bool Fall()//下落 
{
    bool fall=false;int down=1;
    for(short int i=1;i<=5;++i)
    {
        for(short int j=1;j<=7;++j)
        {
            if(g[i][j]==0)
            {
                down=1;
                for(short int k=j+1;k<=7;++k)
                {
                    if(g[i][k]==0)
                        ++down;
                    else
                    {
                        swap(g[i][k-down],g[i][k]);
                    }
                }
                fall=true;
                break;
            }
        }
    }
    for(short int i=1;i<=5;++i)
    {
        top[i]=1;
        while(g[i][top[i]]!=0&&top[i]<8)
            ++top[i];
        top[i]--;
    }
    return fall;
}
inline bool Del()//删除 
{
    bool del=false;
    Fall();
    short int cop[6][8];
    for(short int i=1;i<=5;++i)
        for(short int j=1;j<=7;++j)
            cop[i][j]=g[i][j];
    for(short int i=1;i<=5;++i)//竖直方向查找删除 
    {
        for(short int j=1;j<=top[i]-2;++j)
        {
            if(cop[i][j]==cop[i][j+1]&&cop[i][j+1]==cop[i][j+2])
            {
                g[i][j]=g[i][j+1]=g[i][j+2]=0;
                del=true;
            }
        }
    }
    for(short int i=1;i<=3;++i)//以某一个为最左端横向删除 
    {
        for(short int j=1;j<=top[i];++j)
        {
            if(cop[i][j]==cop[i+1][j]&&cop[i][j]==cop[i+2][j])
            {
                g[i][j]=g[i+1][j]=g[i+2][j]=0;
                del=true;
            }
        }
    }
    if(del)
        Del();
    return del;
}
inline bool Blank()//图空 
{
    //Fall(); 
    for(short int i=1;i<=5;++i)
        if(top[i]!=0)
            return false;
    return true;
}
inline bool Count()//计算每一种颜色的个数判断是否合法
{
    short int vis[12];
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=5;++i)
        for(int j=1;j<=top[i];++j)
            vis[g[i][j]]+=1;                
    for(int i=1;i<=10;++i)
        if(vis[i]==1||vis[i]==2)
            return false;
    return true;
}
inline bool Special_Judge()
{
    Fall();
    if(n==5&&top[1]==1&&g[1][1]==2&&top[2]==4&&top[3]==6&&top[4]==7&&top[5]==7)
    {
        printf("1 1 -1\n2 4 1\n3 2 1\n3 6 1\n3 3 1\n");
        return true;
    }
    return false;
}

Day2

T1计算系数

二项式定理直接搞就行了。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

#define Mod 10007
#define ll long long

ll Pow(ll a,ll b)
{
    if(b==0)return 1;
    if(b==1)return a;
    int s=1;
    s=Pow(a,b/2)%Mod;
    if(b%2==0)
        return s*s%Mod;
    else
        return s*s%Mod*a;   
}

int main()
{
    ll a,b,k,m,n;
    cin>>a>>b>>k>>m>>n;
    ll ans=Pow(a,m)*Pow(b,n)%Mod;
    ll C=1;
    ll t=min(m,n);
    for(ll i=k;i>k-t;--i)
        C=C*i%Mod;
    for(ll i=2;i<=t;++i)
        C=C*Pow(i,Mod-2)%Mod;
    cout<<ans*C%Mod<<endl;
    return 0;
}

T2聪明的质检员

一道还不错的题目
二分W值,前缀和统计结果就行了(前缀和我竟然还没有一下就想到。。。。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 2001000
#define INF 1e14
#define ll long long
inline ll read()
{
      register ll x=0,t=1;
      register char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
      if(ch=='-'){t=-1;ch=getchar();}
      while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
      return x*t;
}
int N,M;
int W[MAX],V[MAX],L[MAX],R[MAX],A[MAX];
ll B[MAX],S,ans=INF;
ll Count(int WW)
{
    memset(A,0,sizeof(A));
    memset(B,0,sizeof(B));
    for(int i=1;i<=N;++i)
        if(W[i]>=WW)
            A[i]=1,B[i]=V[i];
    for(int i=1;i<=N;++i)A[i]+=A[i-1],B[i]+=B[i-1];
    ll tot=0;
    for(int i=1;i<=M;++i)
        tot+=1LL*(A[R[i]]-A[L[i]-1])*(B[R[i]]-B[L[i]-1]);
    return tot;
}
int main()
{
    N=read();M=read();S=read();
    for(int i=1;i<=N;++i)W[i]=read(),V[i]=read();
    for(int i=1;i<=M;++i)L[i]=read(),R[i]=read();
    ll l=1,r=INF;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        ll kk=Count(mid);
        ans=min(ans,abs(kk-S));
        if(kk<S)r=mid;
        else l=mid+1;
    }
    printf("%lld\n",ans);
    return 0;
}

T3观光公交

贪心题
很容易想到贪心,每次找一个能够影响最多人的路径。
每个点出发时间一定在最后一个人到达的时间之后
因此每次找的时候,计算一下每一条边最多能够向后影响多少人,
取最大值,然后重复计算
O(nk)的复杂度可以接受(其实当然可以更快啦)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 101000
inline int read()
{
    register int x=0,t=1;
    register char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-'){t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    return x*t;
}
int n,m,k,d[MAX],T[MAX],fr[MAX],to[MAX],lst[MAX],down[MAX];
int us[MAX],nn,mm,ans,ss[MAX],tt[MAX];
int main()
{
    n=read();m=read();k=read();
    for(int i=1;i<n;++i)d[i]=read();
    for(int i=1;i<=m;++i)
    {
        T[i]=read();fr[i]=read();to[i]=read();
        lst[fr[i]]=max(lst[fr[i]],T[i]);//某一个景点最后一个人出现的时间
        down[to[i]]++;//统计下车人数
    }
    for(int i=2;i<=n;++i)tt[i]=max(tt[i-1],lst[i-1])+d[i-1];
    for(int i=1;i<=n;++i)ss[i]=ss[i-1]+down[i];
    for(int i=1;i<=m;++i)ans+=tt[to[i]]-T[i];
    us[n]=us[n-1]=n;//用一个加速器可以影响的最后一条边
    tt[1]=lst[1];
    while(k--)
    {
        for(int i=2;i<=n;++i)
            tt[i]=max(tt[i-1],lst[i-1])+d[i-1];//计算每一个站到达的时间
        for(int i=n-2;i;--i)
            us[i]=tt[i+1]<=lst[i+1]?i+1:us[i+1];
        nn=mm=0;
        for(int i=1;i<n;++i)
        {
            if(ss[us[i]]-ss[i]>nn&&d[i])
            {
                nn=ss[us[i]]-ss[i];
                mm=i;
            }
        }
        ans-=nn;d[mm]--;
    }
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值