ACM Steps_Chapter Nine_Section1

A == B ?

/*
测试数据:

        0   -0

        0   +0

        123.123     +00123.12300

         100.00       100

          .1     0.1

          000.000     0

          123456789123456789       123456789123456789

          1     1

           000001000.      1000
		   */
#include <stdio.h>
#include <string.h>

void A(char *s)
{
    int len = strlen(s);
    char *p = s + len - 1;
    if (strchr(s, '.'))
    	while (*p == '0')
			 *p-- = 0;
    if (*p == '.') 
		*p = 0;
}

int main(void)
{
    char *pa, *pb;
    char a[100024], b[100024];

    while (scanf("%s%s", &a, &b) != EOF)
    {
        pa = a; 
		pb = b;
        while (*pa == '0') 
			pa++;
        while (*pb == '0') 
			pb++;
        A(pa); 
		A(pb);
        puts(strcmp(pa, pb) ? "NO" : "YES");
    }

    return 0;
}

Doing Homework again

/*
题目大意:给定一系列任务的截至时间 和无法完成的罚分
解题思路:第N天截至的只能在前N天完成 对于第N天截至的任务 最多只能有N个
超出的必然无法完成 所以对于第N天截至的任务 如果超过N个 那么保留前N大的
后面的必然要罚分 然后从最后一天开始 所有截至日期大于当天的中的罚分最多的任务在当天完成
剩下的继续在下一天继续比较 在开始的时候记录总是罚分sum  用sum减去每次完成的任务的罚分
最后sum即是总是罚分
*/
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int v[1001];
struct Node
{
    int d,s;
}a[1001],b[1001];
 
bool cmp(Node x,Node y)
{
     if(x.d!=y.d)
     return x.d<y.d;
     else
     return x.s>y.s;
}
 
int main()
{
    int t;
    cin>>t;
    for(int l=1;l<=t;l++)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(v,0,sizeof(v));
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i].d;
            int sum=0;
        for(int i=1;i<=n;i++)
            {
                cin>>a[i].s;
                sum+=a[i].s;
            }
        sort(a+1,a+n+1,cmp);
        int day=0;
        int k=1,kk=1;
        for(int i=1;i<=n;i++)
        {
          if(a[i].d!=day)
          {
              day=a[i].d;
              k=1;
          }
          else
          {
              k++;
          }
          if(k<=a[i].d)
          {
              b[kk].d=a[i].d;
              b[kk++].s=a[i].s;
          }
        }
        sort(b+1,b+kk,cmp);
        int p=b[kk-1].d;
        for(int i=p;i>=1;i--)
        {
            int Max=0;
            int kkk=0;
            for(int j=kk-1;j>=1;j--)
            {
                if(b[j].d>=i&&!v[j])
                {
                    if(b[j].s>Max)
                    {
                        Max=b[j].s;
                        kkk=j;
                    }
                }
            }
            sum-=Max;
            v[kkk]=1;
            }
            cout<<sum<<endl;
        }
    return 0;
}

FATE

/*
二维背包,dp[i][j]表示忍耐度为i,且还可以杀j个怪时能获得的最大经验值

dp[i][j]=max(dp[i][j],dp[i-r[k]][j-1]+e[k]),r[k]为杀死第k种怪掉的忍耐度,
e[k]为第k种怪的经验值

注意方程转移时,我们必须要保证考虑第j个阶段时,我们只放入背包中1个怪,也就是说,
必须做01背包,不能做完全背包

一开始先枚举的就,再枚举k,再从小到大枚举i,这样就变成做完全背包了,
第k类怪可能在同一阶段被放入多次,如果从大到小枚举i就没问题了
*/
#include<stdio.h>
#include<string.h>
#define max(a,b) (a)>(b)?(a):(b)
int dp[101][101];
int v[101],r[101];
int main()
{
   int n,m,k,s,i,j,l;
   while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF)
   {
       for(i=0;i<k;i++)
	      scanf("%d%d",&v[i],&r[i]);
		  memset(dp,0,sizeof(dp));
		  for(i=0;i<k;i++)
		     for(j=r[i];j<=m;j++)
				 for(l=1;l<=s;l++)
                    dp[j][l]=max(dp[j][l],dp[j-r[i]][l-1]+v[i]);
		int flag=0;
		for(i=0;i<=m;i++)//遍历满足的经验的最小消耗忍耐度
		{
		    if(flag) break;
			for(j=1;j<=s;j++)//怪的数量限制
			{
			    if(dp[i][j]>=n) 
				{
					j=i;flag=1;break;
				}
			}
		}
		if(!flag) printf("-1\n");
		else printf("%d\n",m-j);
		  	   
   }
   return 0;
}

Solitaire

/*
在一个8×8的棋盘中,给定你4个棋子A,再给你4个棋子B,问你在8步之内能不能够从A位置移动到B位置;

规则:棋子能能上下左右移动,同时能跳过相邻的棋子到达相邻棋子的空地方;

 

这个题要用双向搜索;同时我用一个8维的数组hash来构造一个图;当hash标记为1时表示A到过该点,标记为2时表示B到过该点;

这里要注意就是A,B同时搜索时他们分别最多只能走4步,如果多于4步,那么他们步数之和就可能大于8;

这里还要用到排序,这个很重要,因为4个点是不分形状大小的,那么我们就不会重复走
*/
#include<iostream>
 #include<algorithm>
 #include<queue>
 #include<cstring>
 using namespace std;
 
 char  visited[8][8][8][8][8][8][8][8];//用来保存四个棋子的状态
 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};  //上、下、左、右
 
 struct point {
     int x,y;
 };
 struct node {
     struct point p[4];  //一种状态,四个棋子
     int step;
 };
 //给棋排子序,避免同一个状态重复入队列
 int  cmp(const point &p,const point &q){
     if(p.x==q.x)
         return p.y<q.y;
     return p.x<q.x;
 }
 
 //判断是否可以走 
 int judge(node &s ,int i,int j,int flag){
     if( flag==1 ){
         if( s.step >=4 )//最多移动4步 
             return 0;
         s.step ++;    
     }
     s.p[i].x += dir[j][0];
     s.p[i].y += dir[j][1];
     if(s.p[i].x >= 0&&s.p[i].x < 8 &&s.p[i].y >=0&&s.p[i].y<8 ){
         int k;
         for(k = 0 ; k< 4 ; k++){
             if( i!=k ){
                 if(  s.p[i].x== s.p[k].x&& s.p[i].y==s.p[k].y )//判断是否有点,有点的话,就间隔判断    
                     if( flag==1 ) return judge(s ,i ,j, 0);//判断是否跳过相邻的点可以合法走动 
                     else return 0;    
             }    
         }
         //可以走
         if( k>=4 ){
             sort(s.p,s.p+4,cmp);
             return 1;
         } 
     } 
     return 0;
 }
 
 void bfs(node s1,node s2){
     queue<node>Q1,Q2;
     node ss;
     Q1.push(s1),Q2.push(s2);
     visited[s1.p[0].x][s1.p[0].y][s1.p[1].x][s1.p[1].y][s1.p[2].x][s1.p[2].y][s1.p[3].x][s1.p[3].y]='1';
     visited[s2.p[0].x][s2.p[0].y][s2.p[1].x][s2.p[1].y][s2.p[2].x][s2.p[2].y][s2.p[3].x][s2.p[3].y]='2';
     while((!Q1.empty())||(!Q2.empty())){
         if(!Q1.empty()){
             for(int i=0;i<4;i++){
                 //第i个棋子,搜的方向//这是搜走一步的
                 for(int j=0;j<4;j++){
                     ss=Q1.front();
                     if(judge(ss,i,j,1)){
                         if(visited[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='1')
                             continue;
                         //在Q2中已经搜过
                         if(visited[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='2'){
                             printf("YES\n");
                             return ;
                         }
                         Q1.push(ss);
                         visited[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]='1';//在Q1中搜过的标记为'1';
                     }
                 }
             }
             Q1.pop();//出队列的时候一定要4颗棋子4个方向都试过才能出
         }
         if(!Q2.empty()){
             for(int i=0;i<4;i++){
                 //第i个棋子,搜的方向//这是搜走一步的
                 for(int j=0;j<4;j++){
                     ss=Q2.front();
                     if(judge(ss,i,j,1)){
                         if(visited[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='2')
                             continue;
                         //在Q1中已经搜过
                         if(visited[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]=='1'){
                             printf("YES\n");
                             return ;
                         }
                         Q2.push(ss);
                         visited[ss.p[0].x][ss.p[0].y][ss.p[1].x][ss.p[1].y][ss.p[2].x][ss.p[2].y][ss.p[3].x][ss.p[3].y]='2';  //在Q2中搜过的标记为'2';
                     }
                 }
             }
             Q2.pop();
         }
     }
     printf("NO\n");
 }
 
 
 int main(){
     int x,y;
     while(scanf("%d%d",&x,&y)!=EOF){
         node s1,s2;
         s1.p[0].x=x-1,s1.p[0].y=y-1;
         for(int i=1;i<4;i++){
             scanf("%d%d",&x,&y);
             s1.p[i].x=x-1,s1.p[i].y=y-1;
         }
         for(int i=0;i<4;i++){
             scanf("%d%d",&x,&y);
             s2.p[i].x=x-1,s2.p[i].y=y-1;
         }
         s1.step=s2.step=0;
         sort(s1.p,s1.p+4,cmp);
         sort(s2.p,s2.p+4,cmp);
         memset(visited,0,sizeof(visited));
         bfs(s1,s2);
     }
     return 0;
 }

Building Block

#include<stdio.h>
#include<string.h>
int num[333333];
int set[333333];
int under[333333];
int find(int x)
{
    int tmp;
    if (x!=set[x])
    {
        tmp = find(set[x]);
        under[x] += under[set[x]];
        set[x] = tmp;
    }
    return set[x];

}
void merge(int a,int b)
{
    int fx=find(a);
    int fy=find(b);
    if(fx!=fy)
    {
        under[fx]=num[fy];
        num[fy]+=num[fx];
        set[fx]=fy;
    }
}
int main()
{
    int n,a,b;
    char s[5];
    while(scanf("%d",&n)!=EOF)
    {
        memset(under,0,sizeof(under));
        for(int i=0; i<=n; i++)//初始化
        {
            set[i]=i;
            num[i]=1;
        }
        for(int i=0; i<n; i++)
        {
            scanf("%s",s);
            if(s[0]=='M')
            {
                scanf("%d%d",&a,&b);
                merge(a,b);
            }
            else
            {
                scanf("%d",&a);
                find(a);
                printf("%d\n",under[a]);
            }
        }
    }
    return 0;
} 
/*
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
*/

Life is a Line

/*
题目大意:求交点的x坐标落于开区间(l,r)的直线对对数.

思路:设直线和x=l交于(l,h1),和x=r交于(r,h2),按照h1降序排序(h1相等的按照h2降序).
得到一个h2数列,求这个h2数列的顺序数(i<j && h2[i]<h2[j]),可以用线段树或树状数组.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define ull unsigned __int64
#define ll __int64
//#define ull unsigned long long
//#define ll long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define middle (l+r)>>1
#define MOD 1000000007
#define esp (1e-4)
const int INF=0x3F3F3F3F;
const double DINF=10001.00;
//const double pi=acos(-1.0);
const int N=50010;
int n,m;
int sum[N];
double hash[N],L,R;
struct node{
	double h1,h2;
	bool operator < (const node& p) const {
		if(h1==p.h1) return h2 > p.h2;
		return h1 > p.h1;
	}
}a[N];

int lowbit(int x){return x&(-x);}

void Add(int pos,int c){
	while(pos<=m+1) sum[pos]+=c,pos+=lowbit(pos);
}

int Sum(int pos){
	int r=0;
	while(pos>0) r+=sum[pos],pos-=lowbit(pos);
	return r;
}

int bs(double key,int size,double A[]){
	int l=0,r=size-1,mid;
	while(l<=r){
		mid=middle;
		if(key==A[mid]) return mid;
		else if(key>A[mid]) l=mid+1;
		else if(key<A[mid]) r=mid-1;
	}
	return -1;
}

int main(){
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	int i,j,k,pos,ret;
	//int T,cas;scanf("%d",&T);for(cas=1;cas<=T;cas++)
	while(~scanf("%d",&n)){
		scanf("%lf%lf",&L,&R);
		for(i=j=k=0;i<n;i++){
			double x1,y1,x2,y2;
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			if(x1==x2){
				if(L<x1 && x1<R) k++;
			}else{
				a[j].h1=(L-x1)*(y1-y2)/(x1-x2)+y1;
				hash[j]=a[j].h2=(R-x1)*(y1-y2)/(x1-x2)+y1;
				j++;
			}
			
		}
		sort(hash,hash+j);
		for(i=m=1;i<j;i++) if(hash[i]!=hash[i-1]) hash[m++]=hash[i];
		sort(a,a+j);
		memset(sum,0,sizeof(sum));
		for(i=ret=0;i<j;i++){
			pos=bs(a[i].h2,m,hash);
			ret+=Sum(pos);
			Add(pos+1,1);
		}
		printf("%d\n",ret+k*j);
	}
	return 0;
}

Travel

/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
    Copyright (c) 2011 panyanyany All rights reserved.

    URL   : http://acm.hdu.edu.cn/showproblem.php?pid=2433
    Name  : 2433 Travel

    Date  : Wednesday, January 25, 2012
    Time Stage : 4 hours

    Result: 
5292805	2012-01-25 14:24:31	Accepted	2433
656MS	324K	2494 B
C++	pyy


Test Data :

Review :
不说了,直接上大牛的解题报告:
http://isomer.me/2011/08/hdu-2433-%E6%9C%80%E7%9F%AD%E8%B7%AF%E9%A2%84%E5%A4%84%E7%90%86/
http://hi.baidu.com/novosbirsk/blog/item/5c26bffbd04d4d6c034f56b7.html
//----------------------------------------------------------------------------*/

#include <cstdio>
#include <CSTRING>

#include <queue>
#include <algorithm>
#include <vector>

using namespace std ;

#define MEM(a, v)		memset (a, v, sizeof (a))	// a for address, v for value
#define max(x, y)		((x) > (y) ? (x) : (y))
#define min(x, y)		((x) < (y) ? (x) : (y))

#define INF		(0x3f3f3f3f)
#define MAXN	102

struct EDGE {
	int u, v ;
} ;

bool	used[MAXN], bCnet, bInit ;
int		n, m ;
int		dist[MAXN], map[MAXN][MAXN], sum_d[MAXN], pre[MAXN][MAXN] ;

EDGE	e[30*MAXN] ;

int bfs (int beg)
{
	int i, t ;
	queue<int>	q ;

	MEM (used, 0) ;
	MEM (dist, 0) ;

	used[beg] = 1 ;
//	dist[beg] = 0 ;
	q.push (beg) ;

	while (!q.empty ())
	{
		t = q.front() ;
		q.pop () ;

		for (i = 1 ; i <= n ; ++i)
		{
			if (!used[i] && map[t][i])
			{
				used[i] = 1 ;
				dist[i] = dist[t] + 1 ;
				// 只有要第一次 bfs 计算各边的时候才用到
				if (bInit)
					pre[beg][i] = t ;
				q.push (i) ;
			}
		}
	}
	int tmpSum = 0 ;
	// 从 beg+1 开始 和从 1 开始,效果差不多
	for (i = beg + 1 ; i <= n ; ++i)
	{
		if (!dist[i])
			return INF ;
		tmpSum += dist[i] ;
	}
	return tmpSum ;
}

int main ()
{
	int i, j ;
	int u, v, sum, res ;
	while (scanf ("%d%d", &n, &m) != EOF)
	{
		MEM (map, 0) ;
		MEM (pre, 0) ;

		for (i = 1 ; i <= m ; ++i)
		{
			scanf ("%d%d", &u, &v) ;
			e[i].u = u ;
			e[i].v = v ;
			map[u][v] = ++map[v][u] ;
		}

		sum = 0 ;
		bCnet = true ;
		bInit = true ;
		for (i = 1 ; i <= n ; ++i)
		{
			sum_d[i] = bfs (i) ;
			sum += sum_d[i] ;

			// 优化……很显然效果不大
			if (sum >= INF)
			{
				bCnet = false ;
				break ;
			}
		}
		bInit = false ;

		for (i = 1 ; i <= m ; ++i)
		{
			u = e[i].u ;
			v = e[i].v ;
			// map[u][v] 判断有无重边,可以优化300多MS
			if (bCnet && map[u][v] == 1)
			{
				res = 0 ;
				for (j = 1 ; j <= n ; ++j)
				{
					// 最重要的剪枝,否则直接超时
					if (pre[j][u] != v && pre[j][v] !=u)
						res += sum_d[j] ;
					else
					{
						--map[u][v] ;
						--map[v][u] ;
						res += bfs (j) ;
						++map[u][v] ;
						++map[v][u] ;

						if (res >= INF)
							break ;
					}
				}
			}
			else    // 一开始漏了这句,一直无限WA,气死了,思维漏洞啊!
				res = sum ;
			if (res >= INF)
				puts ("INF") ;
			else
				printf ("%d\n", res * 2) ;
		}
	}
	return 0 ;
}

Perfect Squares

/*
先打表,找规律

#include<iostream>  
#include<set>  
using namespace std;  
int main()  
{  
    set<long long>myset;  
    for(long long i=1;i<20;i++,cout<<endl)  
    {  
        myset.clear();  
        for(long long j=0;j<1000000;j++)   
            myset.insert(j*j%(1<<i));  
        cout<<i<<' '<<myset.size();  
    }  
    return 0;  
}  

f(i)=4*f(i-2)-5    通项    f(i)=(2^(n-1)+5)/3           i为奇数
f(i)=4*f(i-2)-4                f(i)=(2^(n-1)+4)/3           i为偶数
即 f(i)=(2^(n-1)+4+n%1)/3
若b%c=1,则a/b%c=a%c=d,证明如下:
b=c*k1+1   a=b*(c*k2+d)=(c*k1+1)*(c*k2+d)=c*(k1*k2+k1*d+k2)+d=c*k3+d
因此a%c=d=a/b%c
求解f(i)%mod,a/b%c=(a*k)/(b*k)%c=a*k%c,(b*k%c=1)
即求任一k使b*k%c=1,  即b*k=c*k'+1,设x=k,y=-k’,则x*b+y*c=1,extgcd或者打表求一个x即可

#include<iostream>  
using namespace std;  
int extgcd(int &x,int &y,int a,int b)  
{  
    if(b==0){x=1,y=0;return a;}  
    int d=extgcd(x,y,b,a%b);  
    int t=x;x=y;y=t-a/b*y;  
    return d;  
}  
int main()  
{  
    int x,y;  
    extgcd(x,y,3,10007);  
    cout<<x<<endl;  
}  
#include<iostream>  
using namespace std;  
int main()  
{  
    for(int i=1;i<1000000;i++)  
        if(i*3%10007==1)  
        {  
            cout<<i<<endl;break;  
        }  
}  

所以f(i)=(2^(n-1)+4+n%1)*3336%10007.
*/
#include<iostream>  
using namespace std;  
typedef long long ll;  
const ll mod=10007;  
ll pow(ll n)  
{  
    ll ans=1,base=2;  
    while(n)  
    {  
        if(n&1) ans=ans*base%mod;  
        base=base*base%mod,n>>=1;  
    }  
    return ans;  
}  
int main()  
{  
    ll t,n,cas=1;  
    cin>>t;  
    while(t--)  
    {  
        cin>>n;  
        cout<<"Case #"<<cas++<<": "<<3336*(pow(n-1)+4+(n&1))%mod<<endl;  
    }  
    return 0;  
} 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值