• 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;
    }
    
    
    
  • 相关阅读:
    开源 免费 java CMS
    运行shell脚本报错 &#39;357273277&#39;: command not found 解决的方法
    Android学习笔记之Spinner下拉列表使用案例
    HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)
    DrawerLayout
    云计算设计模式(十三)——领导人选举模式
    算法之贪心思想
    [Android]Volley源代码分析(叁)Network
    oracle TABLE ACCESS BY INDEX ROWID 你不知道的索引回表-开发系列(三)
    JavaScript No Overloading 函数无重载之说
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7581184.html
Copyright © 2020-2023  润新知