HDU_Steps9.1 杂题 HDU2054 HDU1789 HDU2159 HDU1401 HDU2818 HDU3465 HDU2433 HDU3524

HDU2054 A == B ?

坑爹题,题意说的太不清楚了。注意几点,前面的0,有小数点时后面的0,以及正负数(不同号时仅有0相等)

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main(){
	string s1,s2;
	while(cin>>s1>>s2){
		int l1=s1.size()-1;//后面
		int l2=s2.size()-1;
		int r1=0,r2=0;//前面
		//记录符号是否相同符号
		bool ff=true;
		if((s1[0]=='-'&&s2[0]!='-')||(s2[0]=='-'&&s1[0]!='-')){
			ff=false;
		}
		//如果有小数点去后面的0
		if(s1.find('.')!=string::npos){
			while(l1>=0){
				if(s1[l1]>='1'&&s1[l1]<='9')break;
				if(s1[l1]=='.'){l1--;break;}
				l1--;
			}
		}
		if(s2.find('.')!=string::npos){
			while(l2>=0){
				if(s2[l2]>='1'&&s2[l2]<='9')break;
				if(s2[l2]=='.'){l2--;break;}
				l2--;	
			}
		}		
		//去前面的0;
		while(r1<l1){
			if((s1[r1]>='1'&&s1[r1]<='9')||s1[r1]=='.')break;
			r1++;
		}
		while(r2<l2){
			if((s2[r2]>='1'&&s2[r2]<='9')||s2[r2]=='.')break;
			r2++;
		}
		//剩下的长度
		if(r2-l2!=r1-l1){
			printf("NO\n");
			continue;
		}
		if(ff==false&&s2[r2]=='0'){
			printf("YES\n");
			continue;	
		}
		//比较
		bool flag=true;
		for(int i=r2,j=r1;i<=l2&&j<=l1;i++,j++){
			if(s1[j]!=s2[i])flag=false;	
		}
		printf(flag&&ff?"YES\n":"NO\n");
	}
	return 0;
}


HDU1789 Doing Homework again

一道简单谈心,分值大的先安排,并且尽量靠后,不能安排的就减去该分值

HDU2159 FATE

有一定的精力值,和杀怪上限,升级需要一定的经验值,问最大能保留多少忍耐度,DP

#include<cstdio>
#include<string.h>
using namespace std;
int n,m,k,s,a[101],b[101];
/*一边扯淡一边乱写就A了。。
 * 就是一个无穷物品的背包,d[i]表示这一点可达到的最大经验,d2[i]表示达到这一经验最少要杀多少只怪
 * 优先DP经验,经验相同时使只数最少
 * 最后从头扫描一遍,找出经验足够且只数在范围内的最小耗费精力值
 */
int main(){
	while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF){
		for(int i=1;i<=k;i++)scanf("%d%d",&a[i],&b[i]);
		//DP
		int d[105],d2[105];
		memset(d,-1,sizeof d);
		memset(d2,-1,sizeof d2);
		d[0]=d2[0]=0;
		for(int i=1;i<=k;i++){
			for(int j=b[i];j<=m;j++){
				if(d[j-b[i]]!=-1&&d[j-b[i]]+a[i]>d[j]){
					d[j]=d[j-b[i]]+a[i];
					d2[j]=d2[j-b[i]]+1;
				}
				if(d[j-b[i]]!=-1&&d[j-b[i]]+a[i]==d[j]&&d2[j]>d2[j-b[i]]+1){
					d2[j]=d2[j-b[i]]+1;	
				}
			}	
		}
		
		bool flag=false;
		for(int i=1;i<=m;i++){
			if(d[i]>=n&&d2[i]<=s){
				printf("%d\n",m-i);
				flag=true;
				break;	
			}
		}
		if(!flag)printf("-1\n");
		
	}
	return 0;	
}

HDU1401 Solitaire

每次可移动一步或跳过一步,给定初始态和终态,问是否在八步内可达。我的第一道双向广搜,每个方向只搜4层,如果当前的状态已经在另一个方向中访问过了就说明在8步内可达,标记访问用的是char类型,这样才能保证不超内存。

#include<cstdio>
#include<queue>
#include<algorithm>
#include<string.h>
using namespace std;
struct node{
	int r,c;	
	bool operator <(const node& n)const{
		return r<n.r||(r==n.r&&c<n.c);	
		
	}
};
struct state{
	node nd[4];
	int step;
}sta,end;
int st[8],en[8];
int dr[]={1,0,-1,0},dc[]={0,1,0,-1};
char vis[8][8][8][8][8][8][8][8];//0代表未访问,1代表正向,2代表反向(short(正好32M)和int都会超)
void visit(state s,char v){
	sort(s.nd,s.nd+4);
	vis[s.nd[0].r][s.nd[0].c][s.nd[1].r][s.nd[1].c][s.nd[2].r][s.nd[2].c][s.nd[3].r][s.nd[3].c]=v;
}
char gvisit(state s){
	sort(s.nd,s.nd+4);
	return vis[s.nd[0].r][s.nd[0].c][s.nd[1].r][s.nd[1].c][s.nd[2].r][s.nd[2].c][s.nd[3].r][s.nd[3].c];
}
bool inbfs(queue<state> &q,short now,short opp){
	state ost=q.front();q.pop();
	if(ost.step>4)return false;//每个队列只搜四步
	
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			state nst=ost;
			int nr=nst.nd[i].r+dr[j];
			int nc=nst.nd[i].c+dc[j];
			bool jump2=false,canmv=true;
			for(int k=0;k<4;k++){//如果有点已经在这个位置了,就再向这个方向走一步
				if(i==k)continue;
				if(ost.nd[k].r==nr&&ost.nd[k].c==nc){
					nr+=dr[j],nc+=dc[j];
					jump2=true;
					break;	
				}	
			}
			if(jump2){//如果走了两步步就要再判,如果还重合就不可走了
				for(int k=0;k<4;k++){
					if(i==k)continue;
					if(ost.nd[k].r==nr&&ost.nd[k].c==nc){
						canmv=false;
						break;	
					}	
				}	
			}
			if(canmv&&nr>=0&&nc>=0&&nr<=7&&nc<=7){
				nst.nd[i].r=nr,nst.nd[i].c=nc,nst.step=ost.step+1;
				char v=gvisit(nst);	
				if(v==now)continue;//如果这个点被当前队列访问果
				else if(v==opp)return true;//如果这个点被另一队列访问过,说明再八步内可以走到
				else if(v==0){
					visit(nst,now);
					q.push(nst);	
				}
			}
		}	
	}
	return false;
}
bool bfs(){
	memset(vis,0,sizeof vis);
	queue<state> q1,q2;
	q1.push(sta);
	visit(sta,1);
	q2.push(end);
	visit(end,2);
	
	while(!q1.empty()||!q2.empty()){
		if(!q1.empty()){if(inbfs(q1,1,2))return true;};	
		if(!q2.empty()){if(inbfs(q2,2,1))return true;};
	}
	return false;
}
int main(){
	while(scanf("%d",&st[0])!=EOF){
		for(int i=1;i<8;i++)scanf("%d",&st[i]);	
		for(int i=0;i<8;i++)scanf("%d",&en[i]);	
		for(int i=0;i<4;i++){
			sta.step=end.step=1;
			sta.nd[i].r=st[i*2]-1;
			sta.nd[i].c=st[i*2+1]-1;
			end.nd[i].r=en[i*2]-1;	
			end.nd[i].c=en[i*2+1]-1;	
		}
		printf(bfs()?"YES\n":"NO\n");
	}
	return 0;	
}


HDU2818 Building Block

简单并查集,加入表示这一堆的方块个数以及某一块方块下面有多少个方块的数组

#include<cstdio>
using namespace std;
const int maxn=30003;
int p[maxn],u[maxn],t[maxn];
void init(){
	//父节点,这堆的元素数,某节点下面的方块数
	for(int i=0;i<maxn;i++){
		p[i]=i,t[i]=1,u[i]=0;
	}
}
int find(int x){
	if(x!=p[x]){
		int tmp=find(p[x]);
		u[x]+=u[p[x]];
		p[x]=tmp;
	}
	return p[x];
}
void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx==fy)return;
	p[fx]=fy;
	u[fx]=t[fy];
	t[fy]+=t[fx];
}


int n,a,b;
char op[3];
int main(){
	while(scanf("%d",&n)!=EOF){
		init();
		while(n--){
			scanf("%s",op);
			if(op[0]=='M'){
				scanf("%d%d",&a,&b);
				merge(a,b);	
			}else{
				scanf("%d",&a);
				find(a);
				printf("%d\n",u[a]);
			}
		}	
	}
	return 0;
}


HDU3465 Life is a Line

给出N条线段,求在(l,r)内有多少条线段相交,其实是求逆序对。。

#include<cstdio>
#include<algorithm>
using namespace std;
/*给出N条线段,求在(l,r)内有多少条线段相交,用li表示直线与l的交点,ri同理
 *对于l1<l2弱r2>r1则会相交,转化未求逆序对,用归并排序即可
 * 注意处理x2=x1(x1在(l,r)内会与所有非竖直直线相交)的情况以及l1=l2的情况(l相等时按r排序)
 * */
struct point{
	double l,r;	
	bool operator<(const point& p)const{
		return l<p.l(l==p.l&&r<p.r);	
	}
}p[50005];
double ll,rr,x1,y1,x2,y2,ar[50005],tar[50005];
int n,ps,sz,rs;
void merge(int l,int m,int r){
	int l1=l,l2=m+1,pp=0;
	while(l1<=m&&l2<=r){
		if(ar[l1]<=ar[l2]){
			tar[pp++]=ar[l1++];	
		}else{
			tar[pp++]=ar[l2++];
			rs+=m-l1+1;
		}
	}
	while(l1<=m)tar[pp++]=ar[l1++];
	while(l2<=r)tar[pp++]=ar[l2++];
	for(int i=l,j=0;i<=r;i++,j++){
		ar[i]=tar[j];	
	}
}
void mergesort(int l,int r){
	if(l>=r)return;
	int m=(l+r)/2;
	mergesort(l,m);
	mergesort(m+1,r);
	merge(l,m,r);
}

int main(){
	 while(scanf("%d",&n)!=EOF){
		scanf("%lf%lf",&ll,&rr); 
		sz=0,ps=0;
		for(int i=0;i<n;i++){
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			if(x2==x1){
				if(ll<x1&&x1<rr)sz++;	
			}else{
				p[ps].l=y1+(y2-y1)*(ll-x1)/(x2-x1);
				p[ps].r=y1+(y2-y1)*(rr-x1)/(x2-x1);
				ps++;
			}
		}
		sort(p,p+ps);
		for(int i=0;i<ps;i++)ar[i]=p[i].r;
		
		rs=0;
		mergesort(0,ps-1);
		rs+=sz*ps;
		printf("%d\n",rs);
	}
	
	return 0;	
}


HDU2433 Travel

问减去每一条路后剩余的每两点间的最短路和。做法比较暴力,先对每一个点BFS,求出每个点到其它所有点的最短路和,并标记”最短路树“中的边。然后删边时如果该边在该点生成的最短路树中,就重新BFS,若不在,就直接取记录的值。

#include<cstdio>
#include<string.h>
#include<queue>
using namespace std;
int n,m;
struct edge{
	short u,v,n,i;
}ed[6002];
short first[105],vis[105];
int sl[105];
bool flag,hash[105][3005];
void adde(short u,short v,short ind){
	ed[ind].u=u,ed[ind].v=v,ed[ind].i=ind%m;
	ed[ind].n=first[u];
	first[u]=ind;
}
void bfs(short st,int bj){//传入起点和要去的边,bj=-1时代表是初始化
	memset(vis,0,sizeof vis);
	vis[st]=1;
	queue<short> q;
	q.push(st);
	
	while(!q.empty()){
		int t=q.front();q.pop();
		for(int i=first[t];i!=-1;i=ed[i].n){
			int v=ed[i].v;
			if(vis[v]||ed[i].i==bj)continue;
			vis[v]=vis[t]+1;
			if(bj==-1){
				hash[st][ed[i].i]=1;//标记“最短路生成树”
			}
			q.push(v);
		}	
	}
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(first,-1,sizeof first);
		memset(hash,0,sizeof hash);
		memset(sl,0,sizeof sl);
		flag=true;//标记是否连通
		
		short tu,tv;
		for(int i=0;i<m;i++){//邻接表存图
			scanf("%hd%hd",&tu,&tv);	
			adde(tu,tv,i);
			adde(tv,tu,m+i);
		}
		bool fir=true;
		for(int i=1;i<=n&&flag;i++){//预处理,求出每个点到其它点集的最短路和
			bfs(i,-1);
			if(fir){//判断是否连通,注意只要进行一次
				for(int j=1;j<=n;j++)if(!vis[j])flag=false;
				fir=false;	
			}	
			for(int j=1;j<=n;j++){
				sl[i]+=vis[j]-1;
			}
		}
		for(int i=0;i<m;i++){
			if(flag==false){//图不连通,去边必然不连通
				printf("INF\n");
				continue;
			}
			int res=0;
			for(int j=1;j<=n&&flag;j++){
				if(hash[j][i]==0){//如果该点的最短路树不包含i边,去了也没有影响
					res+=sl[j];
				}else{//否则重新bfs,注意去掉第i边
					bfs(j,i);
					for(int k=1;k<=n;k++)if(!vis[k])flag=false;//看是否连通
					if(flag){
						for(int k=1;k<=n;k++){
							res+=vis[k]-1;
						}		
					}
				}
			}	
			if(flag==false){//去边后导致不连通
				printf("INF\n");
				flag=true;
			}else{
				printf("%d\n",res);	
			}
		}
 
		
	}
	return 0; 	
}


HDU3524    Perfect Squares

i^2 mod 2^n (i<n)会有多少个不同的结果,数学真是做不来,还好能打表找到规律

#include<cstdio>
#include<vector>
#include<string.h>
using namespace std;
/* 打表找出规律 
 * F(n)=2^(2n-1)-5(2^(2n-2)-1)/3 奇数时
 * F(n)=2^(2n-1)-4(2^(2n-2)-1)/3 偶数时
 */
/* 求(4^(n-1)-1)/3 mod 10007
 * 4^(n-1)-1(mod 10007*3)的结果/3
 * 也可4^(n-1)-1(mod 10007)*inv(3)
 * inv(3) 3x=1 mod 10007
 */
typedef long long LL;
const LL MOD=10007;
int cas;
LL n;
LL pmod(LL p,LL k,LL mod){
	if(k==0)return 1;
	if(k==1)return p;
	LL r=pmod(p,k/2,mod);
	r=(r*r)%mod;
	if(k&1)r=(r*p)%mod;
	return r;
}
int main(){
	scanf("%d",&cas);
	for(int ca=1;ca<=cas;ca++){
		scanf("%lld",&n);
		LL base=(n&1)?5:4;
		n=(n+1)/2;
		LL r=(pmod(4,n-1,MOD)*2)%MOD;
		LL r2=(pmod(4,n-1,MOD*3)+MOD*3-1)%(MOD*3)/3;
		r=(r+MOD-(base*r2)%MOD)%MOD;
		printf("Case #%d: %lld\n",ca,r);
	}
	return 0;	
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值