ACM Steps_Chapter Nine_Section3

Snail’s trouble

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"math.h"
#define N 111
int ans[N];
void init()
{
	ans[5]=272400600;
	ans[6]=9717617;
	ans[7]=898515;
	int k,q;
	double t,temp;
	for(k=8;k<=100;k++)
	{
		t=0;
		temp=1;
		q=0;
		while(t<100)
		{
			t+=k/temp;
			temp++;
			q++;
		}
		ans[k]=q;
	}
}
int main()
{
	init();
	int k;
	while(scanf("%d",&k)!=-1)
		printf("%d\n",ans[k]);
	return 0;
}

Queuing

/*
题意:f代表男,m代表女,给定长度L,有2^L个不同组合的字符串(f、m相间),不能出现fmf和fff,问有几种组合。

思路:只要能找到递推公式就可以马上切掉这题。

设f(n)为字符串长度为n时复合条件的字符串个数,以字符串最后一个字符为分界点,当最后一个字符为m时前n-1个字符没有限制,即为f(n-1);当最后一个字符为f时就必须去除最后3个字符是fmf和fff的情况,在考虑最后两个字符为mf和ff的情况,显然不行;最后3个字符为fmf、mmf和fff、mff时只有当最后3个字符为mmf时前n-3个字符没有限制,即为f(n-3),当为mff时第n-3个字符可能为f因而对前n-3个字符串有限制;最后4个字符为fmff和mmff时mmff可行。这样就讨论完了字符串的构成情况,得出结论:
f(n)=f(n-1)+f(n-3)+f(n-4)
然后就像fibonacci那样构建矩阵用快速幂取模。。。
*/
 #include <cstdio>
 #include <cstring>
 #include <cmath>
 #include <string>
 #include <algorithm>
 #include <iostream>
 using namespace std;
 
 int f[5]={0,2,4,6,9};
 typedef struct In{
     int m[5][5];
 }Matrix;
 Matrix init,unit,F;
 int n,m;
 
 void Init(){
     for(int i=1;i<=4;i++){
         for(int j=1;j<=4;j++){
             if(i==1&&j==1) init.m[i][j]=1;
             else if(i==1&&j==3) init.m[i][j]=1;
             else if(i==1&&j==4) init.m[i][j]=1;
             else if(i==2&&j==1) init.m[i][j]=1;
             else if(i==3&&j==2) init.m[i][j]=1;
             else if(i==4&&j==3) init.m[i][j]=1;
             else init.m[i][j]=0;
             unit.m[i][j]=(i==j);
             F.m[i][j]=0;
         }
     }
     F.m[1][1]=f[4];
     F.m[2][1]=f[3];
     F.m[3][1]=f[2];
     F.m[4][1]=f[1];
 }
 
 Matrix Mul(Matrix a,Matrix b){
     Matrix c;
     for(int i=1;i<=4;i++)
         for(int j=1;j<=4;j++){
             c.m[i][j]=0;
             for(int k=1;k<=4;k++){
                 c.m[i][j]+=a.m[i][k]*b.m[k][j]%m;
                 c.m[i][j]%=m;
             }
         }
     return c;
 }
 
 Matrix Pow(Matrix a,Matrix b){
     while(n){
         if(n&1) b=Mul(a,b);
         a=Mul(a,a);
         n>>=1;
     }
     return b;
 }
 
 int main(){
     
 //    freopen("data.in","r",stdin);
 //    freopen("data.out","w",stdout);
     
     while(scanf("%d%d",&n,&m)!=EOF){
         if(n<5){
             printf("%d\n",f[n]%m);
             continue;
         }
         Init();
         n-=4;
         Matrix x=Pow(init,unit);
         x=Mul(x,F);
         printf("%d\n",x.m[1][1]%m);
     }
     return 0;
 }

胜利大逃亡(续)

#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;
struct state{
	state(int a,int b,int d,int e){r=a,c=b,v=d,st=e;}
	int r,c,v,st;	
};
char map[30][30];
int n,m,t,stx,sty,mint;
int vis[30][30][1100];
int dr[]={1,0,-1,0},dc[]={0,1,0,-1};

int bfs(){
	memset(vis,0,sizeof vis);
	queue<state> q;
	q.push(state(stx,sty,0,0));
	vis[stx][sty][0]=1;
	
	while(!q.empty()){
		state os=q.front();q.pop();
		int r=os.r,c=os.c,v=os.v,st=os.st;//旧的状态参数
		for(int i=0;i<4;i++){
			int nr=r+dr[i],nc=c+dc[i],nv=v,nst=st+1;//新的状态参数	
			if(nst>=t||nr<0||nc<0||nr>=n||nc>=m||map[nr][nc]=='*')continue;//超出时间,范围,以及墙都是不可达位置
			char tc=map[nr][nc];
			if(tc=='^')return nst;//到达终点
			if(tc>='A'&&tc<='J'){//如果到了这个点却没有对应钥匙
				if((nv&(1<<(tc-'A')))==0)continue;	
			}else if(tc>='a'&&tc<='j'){//如果到的这个点有钥匙
				nv^=(1<<(tc-'a'));
			}
			if(!vis[nr][nc][nv]){//如果这个点未被访问过
				vis[nr][nc][nv]=1;
				q.push(state(nr,nc,nv,nst));	
			}

		}	
	}
	return -1;
}
int main(){
	while(scanf("%d%d%d",&n,&m,&t)!=EOF){
		for(int i=0;i<n;i++){
			scanf("%s",map[i]);	
			for(int j=0;j<m;j++){
				if(map[i][j]=='@')stx=i,sty=j;	
			}
		}
		printf("%d\n",bfs());
	}
	return 0;	
}

The Worm Turns

#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 630
char mat[MAX][MAX];
bool visit[MAX][MAX];
int dir[4][2]= {0,1,-1,0,1,0,0,-1};
int n,m,maxx;
int xi,yi,ki,xt,yt,kt;
void dfs(int a,int b,int d,int step)//深搜
{
    if(step>maxx)//更新最大值
    {
        maxx=step;
        xi=xt;
        yi=yt;
        ki=kt;
    }
    int tx=a+dir[d][0],ty=b+dir[d][1];
    if(tx<0||tx>=n||ty<0||ty>=m||visit[tx][ty]==true||mat[tx][ty])
    {
        if(step==0) return;//第一步是不允许转向的
        for(int i=0; i<4; ++i)
        {
            if(i==d) continue;
            tx=a+dir[i][0];
            ty=b+dir[i][1];
            if(0<=tx&&tx<n&&0<=ty&&ty<m&&visit[tx][ty]==false&&!mat[tx][ty])
            {
                visit[tx][ty]=true;
                dfs(tx,ty,i,step+1);
                visit[tx][ty]=false;
            }
        }
    }
    else
    {
        visit[tx][ty]=true;
        dfs(tx,ty,d,step+1);
        visit[tx][ty]=false;
    }

}
int main()
{
    int t,a,b;
    char c;
    for(int cas=1; ~scanf("%d%d",&n,&m); ++cas)
    {
        if(n+m==0) break;
        memset(mat,0,sizeof(mat));
        maxx=0;
        scanf("%d",&t);
        for(; t--;)
        {
            scanf("%d%d",&a,&b);
            mat[a][b]=1;
        }
        //枚举每个点
        for(int i=0; i<n; ++i)
            for(int j=0; j<m; ++j)
                for(int k=0; k<4; ++k)
                    if(!mat[i][j])
                    {
                        xt=i;
                        yt=j;
                        kt=k;
                        visit[i][j]=true;
                        dfs(i,j,k,0);
                        visit[i][j]=false;
                    }
        if(ki==0) c='E';
        if(ki==1) c='N';
        if(ki==2) c='S';
        if(ki==3) c='W';
        printf("Case %d: %d %d %d %c\n",cas,maxx+1,xi,yi,c);
    }
    return 0;
}

T9

/*
字典树,不难。建字典树时对每一点有一个频度值,
每次取这一层上频度最大的字母所在路径所组成的
*/
#include<cstdio>
#include<string.h>
using namespace std;
struct trie{
	trie(){
		for(int i=0;i<26;i++)next[i]=NULL;
		pro=0;
	}
	trie *next[26];
	int pro;
}*root;
int cas,words,k;
char find[105],res[105],bres[105],wd[105];
int bpro;
bool flag;
//对应按键上的字母
int alpha[8][5]={{0,1,2},{3,4,5},{6,7,8},{9,10,11},{12,13,14},{15,16,17,18},{19,20,21},{22,23,24,25}};
int alphas[8]={3,3,3,3,3,4,3,4};
void instrie(char *wd,int pro){
	int len=strlen(wd);
	trie *p=root;
	for(int i=0;i<len;i++){
		int t=wd[i]-'a';
		if(p->next[t]==NULL){
			p->next[t]=new trie;	
		}
		p=p->next[t];
		p->pro+=pro;//字典树上每一点的概率
	}
}
void dfs(int now,int len,trie *tr){
	if(now==len){//标记字典中右对应按键的结果并且选择最大概率的组合
		flag=true;
		if(tr->pro>bpro){
			bpro=tr->pro;	
			for(int i=0;i<now;i++){
				bres[i]=res[i];	
			}
			bres[now]='\0';
		}
		return;
	}
	int t=find[now]-'2';
	for(int i=0;i<alphas[t];i++){
		int r=alpha[t][i];
		if(tr->next[r]==NULL)continue;
		res[now]=r+'a';
		dfs(now+1,len,tr->next[r]);		
	}
	
}

int main(){
	int pro;
	scanf("%d",&cas);
	for(int ca=1;ca<=cas;ca++){
		printf("Scenario #%d:\n",ca);
		scanf("%d",&words);
		root=new trie;
		for(int i=0;i<words;i++){
			scanf("%s%d",wd,&pro);
			instrie(wd,pro);
		}
		scanf("%d",&k);
		while(k--){
			scanf("%s",find);
			int len=strlen(find);
			for(int i=1;i<len;i++){
				flag=false;
				bpro=0;
				dfs(0,i,root);
				if(flag){
					printf("%s\n",bres);
				}else{
					printf("MANUALLY\n");
				}
			}
			printf("\n");
		}
		printf("\n");
	}
	return 0;	
}

Cycling

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<queue>
//枚举上下界求最短路
using namespace std;
const int inf=1000000000;
struct node{
    int v,i;
    node(int a,int b){v=a,i=b;}
    bool operator <(const node& n)const{
        return v>n.v;
    }    
};
struct ati{
    int l,h;
    bool operator<(const ati& a)const{
        return h-l<(a.h-a.l);    
    }    
}at[100004];
int cas,n,m,h[105],a,b,c;
int map[105][105];
int dij(int low,int high){
    int done[105];
    int d[105];
    for(int i=1;i<=n;i++)d[i]=inf;
    d[1]=0;
    memset(done,0,sizeof done);
    priority_queue<node> pq;
    pq.push(node(d[1],1));
    
    while(!pq.empty()){
        node nd=pq.top();pq.pop();
        int u=nd.i;
        if(done[u]||h[u]<low||h[u]>high)continue;
        done[u]=1;
        for(int v=1;v<=n;v++){
            if(h[v]<low||h[v]>high)continue;
            if(map[u][v]&&d[v]>d[u]+map[u][v]){
                d[v]=d[u]+map[u][v];
                pq.push(node(d[v],v));    
            }
        }
    }
    return d[n];
}
int myabs(int x){return x>0?x:-x;}
int main(){
    int cas;
    scanf("%d",&cas);
    while(cas--){
        memset(map,0,sizeof map);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&h[i]);
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&a,&b,&c);
            if(map[a][b]&&map[a][b]<c)continue;
            map[a][b]=map[b][a]=c;    
        }
        
        int k=0;
        int lmin=min(h[1],h[n]),lmax=max(h[1],h[n]);
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
				if(min(h[i],h[j])>lmin||max(h[i],h[j])<lmax)continue;
                at[k].l=min(h[i],h[j]);
                at[k++].h=max(h[i],h[j]);
            }    
        }
        sort(at,at+k);
        for(int i=0;i<k;i++){
            int d=dij(at[i].l,at[i].h);
            if(d!=inf){
                printf("%d %d\n",at[i].h-at[i].l,d);
                break;        
            }    
        }
    }
    return 0;    
}

Game

/*
能从A取一部分到B,当B<A,并且(A+B)%2=1,(A+B)%3=0,其中A,B是堆的编号

博弈,搞不来啊。将堆数分成两部分,一部分到终态要奇数步,一部分要偶数步。对奇数步的做NIM
*/
#include<cstdio>
using namespace std;
int cas,n,a;
//1,3,4是最终状态,%6为0,2,5为奇数步,对这些堆做NIM游戏
int main(){
	scanf("%d",&cas);
	for(int ca=1;ca<=cas;ca++){
		int rs=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a);
			if(i%6==0||i%6==2||i%6==5)rs^=a;
		}	
		printf("Case %d: ",ca);
		printf(rs?"Alice\n":"Bob\n");
	}
	return 0;	
}

Equations

/*
简单的哈希,但是要注意在a,b,c,d都是正或者都是负的情况要直接排除,否则会TLE
*/
#include<cstdio>
#include<string.h>
using namespace std;
int hash[2000005];
int main(){
	int a,b,c,d;
	while(scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF){
		//注意排除
		if((a>0&&b>0&&c>0&&d>0)||(a<0&&b<0&&c<0&&d<0)){
			printf("0\n");
			continue;	
		}		
		memset(hash,0,sizeof hash);
		for(int i=-100;i<=100;i++){
			for(int j=-100;j<=100;j++){
				if(i&&j)hash[a*i*i+b*j*j+1000000]++;	
			}	
		}
		int rs=0;
		for(int i=-100;i<=100;i++){
			for(int j=-100;j<=100;j++){
				if(i&&j)rs+=hash[-c*i*i-d*j*j+1000000];	
			}	
		}
		printf("%d\n",rs);
	}
	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值