2017 寒假练习题 Part 1

  1. HDU 2516 取石子游戏
    原题链接:Here!
    思路:第一人败的情况是 n=2,3,5,8,13...... 是个斐波那契数列 
    代码:
    /*
    	Note:
    		n=2 	第一人败 * 
    		n=3 	第一人败 *
    		n=4 	第二人败
    		n=5 	第一人败 *
    		n=6 	第二人败
    		n=7 	第二人败
    		n=8	第一人败 *
    		n=9	第二人败 
    		n=10	第二人败 
    		n=11	第二人败 
    		n=12	第二人败 
    		n=13 	第一人败 *
    		
    		这就能很说明问题了 
    */
    // 
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    LL fb[1000];
    int n,i;
    
    void init(){	// 打个第一人败的表 
    	fb[0]=1; fb[1]=1;
    	for(int i=2;i<1000;i++)
    		fb[i]=fb[i-1]+fb[i-2];
    }
    int main(){
    	init();
    	while(~scanf("%d",&n) && n){
    		for(i=2;i<1000 && n!=fb[i] ;i++);	
    		if(i==1000)	printf("First win\n");
    		else		printf("Second win\n");
    	}
    	return 0;
    } 

  2. HDU 1232 畅通工程
    原题链接:Here!
    思路:并查集模板
    代码:
    /*
    	Note:
    		裸并查集 
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000<<1;
    int f[maxn];
    int n,m,a,b;
    
    int getf(int u){
    	if(u==f[u]) return u;
    	f[u]=getf(f[u]);
    	return f[u];
    }
    void marge(int u,int v){
    	int f1,f2;
    	f1=getf(u);	f2=getf(v);
    	if(f1!=f2)
    		f[f2]=f1;
    }
    int main(){
    	while(~scanf("%d",&n) && n){
    		scanf("%d",&m);
    		for(int i=0;i<=n;i++)	f[i]=i;
    		for(int i=0;i<m;i++){
    			scanf("%d%d",&a,&b);
    			marge(a,b);
    		}
    		int cnt=0;
    		for(int i=1;i<=n;i++)
    			if(i==f[i])	cnt++;
    		printf("%d\n",cnt-1); 
    	}
    	return 0;
    } 

  3. HDU 1427 速算24点 ( DP ) ***
    原题链接:Here!
    思路:用next_permutation()代替括号,深搜
    代码:
    #include<bits/stdc++.h>
    using namespace std;
    
    int res[4];
    bool ok;
    
    void dfs(int sum,int cur,int tmp){
    	if(ok)	return;
    	if(cur==3){
    		if(sum+tmp==24)	ok=1;
    		if(sum-tmp==24)	ok=1;
    		if(sum*tmp==24)	ok=1;
    		if(tmp!=0 && sum%tmp==0 && sum/tmp==24)	ok=1;	// 保证分母不为0且能够整除 
    		return;
    	}
    	dfs(sum+tmp,cur+1,res[cur+1]);
    	dfs(sum-tmp,cur+1,res[cur+1]);
    	dfs(sum*tmp,cur+1,res[cur+1]);
    	if(tmp!=0 && sum%tmp==0)	
    		dfs(sum/tmp,cur+1,res[cur+1]);
    	
    	dfs(sum,cur+1,tmp+res[cur+1]);
    	dfs(sum,cur+1,tmp-res[cur+1]);
    	dfs(sum,cur+1,tmp*res[cur+1]);
    	if(res[cur+1]!=0 && tmp%res[cur+1]==0)
    		dfs(sum,cur+1,tmp/res[cur+1]); 
    	
    }
    int main(){
    	char s[3];
    	while(1){
    		for(int i=0;i<4;i++){
    			if(scanf("%s",s)==EOF)	return 0;
    			
    			if(s[0]=='A')	res[i]=1;
    			else if(s[0]=='1' && s[1]=='0')	res[i]=10;
    			else if(s[0]=='J')	res[i]=11;
    			else if(s[0]=='Q')	res[i]=12;
    			else if(s[0]=='K')	res[i]=13;
    			else 	res[i]=s[0]-'0';
    		}
    		sort(res,res+4);
    		ok=0;
    		do{
    			dfs(res[0],1,res[1]);
    		}while(next_permutation(res,res+4) && !ok);
    		if(ok)	printf("Yes\n");
    		else 	printf("No\n");
    	}
    	return 0;
    }
  4. HDU 2059 龟兔赛跑 ( DP ) *** 
    原题链接:Here!
    思路:dp[i] 代表到达第i个充电站的最短时间,dp[i] 可以由状态 dp[j] + T(j~i)转移得到,如果充电注意加上充电时间
    代码:
    /*
    	Note:
    		DP 状态转移方程 
    		dp[i] 可以由状态 dp[j] + T(j~i)转移得到  
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000+10;
    const int INF  = 0x3f3f3f;
    int L,N,C,T,VR,VT1,VT2;
    double  dp[maxn];
    int 	dis[maxn];
    
    void DP(){
    	memset(dp,-1,sizeof(dp));
    	dp[0]=0;
    	for(int i=1;i<=N+1;i++){
    		double Min = INF , ans = 0;
    		for(int j=0;j<i;j++){
    			int L=dis[i]-dis[j];
    			if(L>C)					// 一次充电无法到达 
    				ans = C*1.0/VT1 + (L-C)*1.0/VT2; 
    			else
    				ans = L*1.0/VT1;
    			ans += dp[j];
    			if(j)	ans += T;		// 如果充电加上充电时间 
    			if(Min>ans)	Min=ans;	 
    		}
    		dp[i]=Min;
    	}
    }
    int main(){
    	while(scanf("%d",&L)!=EOF){
    		scanf("%d%d%d",&N,&C,&T);
    		scanf("%d%d%d",&VR,&VT1,&VT2);
    		
    		for(int i=1;i<=N;i++)
    			scanf("%d",&dis[i]);
    		dis[0]=0;	dis[N+1]=L;
    		
    		DP();
    		
    		if(1.0*L/VR < dp[N+1])	printf("Good job,rabbit!\n");
    		else					printf("What a pity rabbit!\n");
    	}
    	return 0;
    }

  5. HDU 2206 IP计算 
    原题链接:Here!
    思路:注意判断IP地址出错的情况即可
    代码:
    /*
    	Note:
    		IP地址被.分成4部分
    		容易出错的地方是
    		1.并没有分成4部分,间隔符不是3个 
    		2.出现非法字符 
    		3.数字没有在0~255之间 
    		4.输入可能有空格 
    		5.可能出现.111.11.1这种情况 
    */ 
    #include<bits/stdc++.h>
    using namespace std;
    
    char ip[110];
    bool ok;
    
    int main(){
    	while(gets(ip)){
    		ok=true;
    		int len=strlen(ip);
    		int cnt=0;
    		
    		if(len>15)	ok=false;
    		for(int i=0;i<len;i++){
    			if(ip[i]=='.') cnt++;
    			else if(ip[i]>='0' && ip[i]<='9')	continue;
    			else{
    				ok=false; break;
    			} 
    		}
    		
    		int t_sum=0;
    		for(int i=0;i<len;i++){
    			if(ip[i]>='0' && ip[i]<='9')
    				t_sum = t_sum*10 + ip[i]-'0'; 
    			if(ip[i]=='.' || i==len-1){
    				if(t_sum>255){
    					ok=false; break;
    				}
    				else	t_sum=0;
    			}
    		}
    		if( cnt != 3 || ip[0]<'0' || ip[0]>'9')	ok=false;	// 特判间隔符和出现 .111.11.1这种情况	
    		if(ok)	printf("YES\n");
    		else	printf("NO\n"); 
    	}
    	return 0;
    }

  6. HDU 2566 统计硬币 
    原题链接:Here!
    代码:
    /*
    	Note:
    		i j k 分别代表1 2 5 分硬币个数 
    		逗#问题 
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    int main(){
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		int n,m;
    		scanf("%d%d",&n,&m);
    		int cnt=0;
    		for(int j=0 ; j<=n ; j++){
    			for(int k=0 ; k<=n ; k++){
    				if(m-2*j-5*k>=0 && (j+k+m-2*j-5*k==n))	cnt++;
    			}
    		}
    		printf("%d\n",cnt);
    	} 
    	return 0;
    } 

  7. HDU 1736 美观化文字
    原题链接:Here!
    思路: Hint 1.你可以认为所有中文字符由两个字节组成   2.string 重载过 + 这一点很好用
    代码:
    /*
    	Note:
    		注意得用gets读,题目介绍是一段话,这段话会有控制符(换行、空格、制表符),所以用gets  
    		题目可能会出现中文引号,如果出现中文引号需要记录出现几次,后面进行匹配
    		这个引号匹配很无语,要求不严格,也没办法严格要求,毕竟是随意输入的一段话 
    */
    #include<bits/stdc++.h>
    using namespace std;
    //#define test
    
    const int maxn = 100000<<1;
    char str[maxn];
    
    int main(){
    	#ifdef test
    		freopen("testData.txt","r",stdin);
    	#endif 
    	while(gets(str)){
    		int L=strlen(str);
    		int cnt=0;
    		for(int i=0;i<L;i++){
    			string tmp="";						// string 重载过+ 很好用 
    			tmp = tmp+str[i]+str[i+1];			// 特殊判断中文引号所需的变量,还可以先用一个程序看一下中文引号的ASCII码直接对比ASCII也行 
    			if(tmp=="“"|| tmp=="”")	cnt++;	// 特殊记录字符串中是否出现过中文引号 
    			if(str[i]=='"'){
    				if(cnt%2==0)	printf("“");
    				else			printf("”"); 
    				cnt++;
    			}
    			else if(str[i]==',')	printf(",");
    			else if(str[i]=='.')	printf("。");
    			else if(str[i]=='!')	printf("!");
    			else if(str[i]=='?')	printf("?");
    			else if(str[i]=='<' && str[i+1]=='<') printf("《"),i++;
    			else if(str[i]=='>' && str[i+1]=='>') printf("》"),i++; 
    			else	printf("%c",str[i]);		// 除转化的字符其余正常输出 
    		}
    		printf("\n"); 
    	}	
    	return 0; 
    }

  8. HDU 1577 WisKey的眼神
    原题链接:Here!
    思路:简单的建立个直线方程
    代码:
    /*
        Note:
            建立直线方程 y = [(ey-sy)/(ex-sx)]*(x-sx)+sy
            非常简单,只需要在开区间(sx,ex)内的存在一个y是整数就不能看到,否则就能看到
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    int L,sx,sy,ex,ey;
    int main(){
        while(scanf("%d",&L)!=EOF && L){
            scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
            if( ex>L || ey>L || ex<-L || ey<-L )   printf("Out Of Range\n");
            else{
            	bool ok=true;
            	if(sx==ex){ // 特殊判断是否在竖轴上 
            		if(abs(sy-ey)>1)	ok=false;
    			}
    			// 接下来能够判断是否在横轴上和斜方向 
            	else{
    				int x1,x2;
    				x1=min(sx,ex);	x2=max(sx,ex);
    				for(int i=x1+1;i<x2;i++){
    					if( (abs(ey-sy)*abs(i-sx)) % abs(ex-sx) == 0 )	{ok=false;break;}
    				}
    			}
    			if(ok)	printf("Yes\n");
    			else	printf("No\n");
            }
        }
        return 0;
    }

  9. HDU 1574 RP问题 ( DP ) ***
    原题链接:Here!
    思路:找到状态转移方程dp[i+a]=max(dp[i+a],dp[i]+c) ,还是弱啊,得苦练
    代码:
    #include<bits/stdc++.h>
    using namespace std;
    
    const int INF = 0x3f3f3f;
    int dp[10020<<1];	// 因为人品最高消耗也就是10000,数组下标不能有负号,右移一倍 
    int T,n,a,b,c;
    
    void DP(){
    	
    }
    int main(){
    	while(scanf("%d",&T)!=EOF){
    		while(T--){
    			scanf("%d",&n);
    			
    			for(int i=0;i<20040;i++)	dp[i] = -INF;
    			int l=10000 , r=10000;	// 定义左右两个游标
    			dp[10000]=0;
    			
    			for(int i=0;i<n;i++){
    				scanf("%d%d%d",&a,&b,&c);
    				b += 10000;	 		// RP门栏值需要右移10000
    				if(a<0){			// 如果这件事情是RP下降 C上升 只能是当前RP值大于RP门栏值 
    					for(int i=b;i<=r;i++) 
    						dp[i+a]=max(dp[i+a],dp[i]+c);
    					l+=a;
    				} 
    				else{
    					for(int i=b;i>=l;i--)
    						dp[i+a]=max(dp[i+a],dp[i]+c);
    					r+=a;
    				}
    			}
    			int ans = -INF;
    			for(int i=l;i<=r;i++)	ans=max(ans,dp[i]);
    			printf("%d\n",ans);
    		}
    	}	
    	return 0;
    } 

  10. HDU 2037 今年暑假不AC
    原题链接:Here!
    思路:典型 选择最多不相交区间问题
    代码:
    /*
    	Note:
    		今年暑假不AC 非常明显的选择不相交区间问题
    		给出n个区间,尽可能多的选出不相交区间 
    		首先对区间尾进行排序, 
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 100<<1;
    struct info{
    	int s,e;
    }Time[maxn];
    int n;
     
    bool cmp(info a,info b){
    	return a.e<b.e;
    }
    int main(){
    	while(scanf("%d",&n)!=EOF && n){
    		for(int i=0;i<n;i++)	scanf("%d%d",&Time[i].s,&Time[i].e); 
    		sort(Time,Time+n,cmp);
    	//	for(int i=0;i<=n;i++)	printf("s = %d, e = %d\n",Time[i].s,Time[i].e);
    		int cnt=1,Mark=0;		// Mark一下上一次选择的节目 
    		for(int i=1;i<n;i++){
    			if(Time[i].s>=Time[Mark].e)	cnt++,Mark=i;
    		}
    		printf("%d\n",cnt);
    	} 
    	return 0;
    }

  11. HDU 2074 叠筐
    原题链接:Here!
    思路:模拟
    代码:
     
    /*
    	Note:	小模拟 
    	NxN 奇整数矩形 填字符 
    	注意N=1时 
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 100;
    char G[maxn][maxn]; 
    int  n;
    char s1,s2;
     
    int main(){
    	int kase=0;
    	while(scanf("%d %c %c",&n,&s1,&s2)!=EOF){
    		if(kase)	printf("\n");
    		kase++;
    		int temp=(n+1)/2;	
    		char str;
    		
    		if(temp%2)  str=s1;
    		else		str=s2;
    		if(n==1)	printf("%c\n",s1);
    		else{
    			for(int k=0;k<temp;k++){
    				for(int i=k;i<n-k;i++){
    					for(int j=k;j<n-k;j++){
    						G[i][j]=str;
    					}
    				}
    				str=str==s1?s2:s1;
    			}
    			G[0][0]=G[0][n-1]=G[n-1][0]=G[n-1][n-1]=' ';
    			for(int i=0;i<n;i++){
    				for(int j=0;j<n;j++){
    					printf("%c",G[i][j]);
    				}
    				printf("\n");
    			}
    		}
    	}
    	return 0;
    }

  12. HDU 1106 排序
    原题链接:Here!
    思路:注意特殊情况,设置一个标记数组Mark[] 记录切割的位置
    代码:
    /*
        Note:  特殊情况 开头或者结尾有 5
        511152225333555
    */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000+10;
    char str[maxn];
    int  Mark[maxn],ans[maxn];
    int main(){
        while(scanf("%s",&str)!=EOF){
            memset(ans,0,sizeof(ans));
            memset(Mark,-1,sizeof(Mark));
            int L = strlen(str);
            int k = 0;
            Mark[0]=-1;
            for(int i=0;i<L;i++)    if(str[i]=='5') Mark[++k]=i;
            Mark[++k]=L;
        //    for(int i=0;i<=k;i++)   printf("%d%c",Mark[i],i==k?'\n':' ');
            int s=0;
            for(int i=0;i<k;i++){
                for(int j=Mark[i]+1;j<Mark[i+1];j++){
                    ans[s] = ans[s]*10 + str[j] - '0';
                }
                if(Mark[i]+1!=Mark[i+1])    // 去掉前后相邻的5的情况
                	s++;
            }
            sort(ans,ans+s);
            for(int i=0;i<s;i++){
                    printf("%d%c",ans[i],i==s-1?'\n':' ');
            }
        }
        return 0;
    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值