zoukankan      html  css  js  c++  java
  • 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
    ",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
    2 4 1
    3 2 1
    3 6 1
    3 3 1
    ");
    		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
    ",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;
    }
    
    
    
  • 相关阅读:
    HDU 3081 Marriage Match II
    HDU 4292 Food
    HDU 4322 Candy
    HDU 4183 Pahom on Water
    POJ 1966 Cable TV Network
    HDU 3605 Escape
    HDU 3338 Kakuro Extension
    HDU 3572 Task Schedule
    HDU 3998 Sequence
    Burning Midnight Oil
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7581184.html
Copyright © 2011-2022 走看看