目录
1001 Sum Problem
#include<iostream>
using namespace std;
int main(){
int n,ans;
while(cin>>n){
ans=0;
for(int i=1;i<=n;i++){
ans+=i;
}
cout<<ans<<endl;
cout<<'\n';
}
return 0;
}
1002 A + B Problem II
vj_hdu1002
大数用字符串进行加法运算
#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
using namespace std;
int main(){
int t;
char a[1010],b[1010];
int ans[1010];
cin>>t;
for(int i=1;i<=t;i++){
memset(ans,0,sizeof(ans));
scanf("%s %s",&a,&b);
cout<<"Case "<<i<<":"<<endl;
cout<<a<<" + "<<b<<" = ";
int la,lb,lm;
la=strlen(a);
lb=strlen(b);
lm=la>lb?la:lb;
int ja,jb,lans,jans,mid;
mid=0;
for(ja=la-1,jb=lb-1,jans=0;ja>=0&&jb>=0;ja--,jb--,jans++){
mid=((a[ja]-48)+(b[jb]-48)+mid);
ans[jans]=mid%10;
mid=mid/10;
}
if(jb>=0){
for(;jb>=0;jb--,jans++){
ans[jans]=((b[jb]-48)+mid)%10;
mid=((b[jb]-48)+mid)/10;
}
}
else if(ja>=0){
for(;ja>=0;ja--,jans++){
ans[jans]=((a[ja]-48)+mid)%10;
mid=((a[ja]-48)+mid)/10;
}
}
if(mid!=0){
ans[jans]=mid;
jans++;
}
for(int j=jans-1;j>=0;j--){
cout<<ans[j];
}
cout<<endl;
if(i!=t)cout<<endl;
}
return 0;
}
1003 Max Sum
求数列的最大的连续子序列和及其位置
假设已经得到最大和的自序列,那么之所以这个自序列不包含前面的几个或者后面几个元素的原因,就是因为前面(或者后面)连续几个元素的和是负数
#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
using namespace std;
int main(){
int t,n,num[100001];
cin>>t;
for(int i=1;i<=t;i++){
cin>>n;
cout<<"Case "<<i<<":"<<endl;
for(int j=0;j<n;j++){
cin>>num[j];
}
int ma=num[0],st=0,ed=0,flag=0;
for(int j=1;j<n;j++){
if(num[j-1]>=0){
num[j]=num[j]+num[j-1];
}
else flag=j;
if(num[j]>ma){
ma=num[j];
ed=j;
st=flag;
}
}
cout<<ma<<" "<<st+1<<" "<<ed+1<<endl;
if(i!=t)cout<<endl;
}
}
1004 Let the Balloon Rise
结构体
#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
using namespace std;
struct node{
char co[20];
int num;
}color[1005];
int main(){
int n;
while(cin>>n){
if(n==0) return 0;
char a[16];
int flag,maxx,add;
for(int t=0;t<n;t++){
cin>>a;
flag=0;
for(int i=0;i<t-1;i++){
if(!strcmp(a,color[i].co)){
flag=1;
color[i].num++;
break;
}
}
if(flag==0){
strcpy(color[t].co,a);
color[t].num=1;
}
}
maxx=0;
for(int t=0;t<n;t++){
if(color[t].num>maxx){
maxx=color[t].num;
add=t;
}
}
cout<<color[add].co<<endl;
}
}
1005 Number Sequence
vj_hdu1005
找循环对,当前值只与前两个数值有关,将数组中连续的两个数视作一个数对,则出现重复数对时数组开始循环。
又
m
o
d
7
⇒
t
mod7\Rightarrow t
mod7⇒t 每个位置上的值只有7种(0~6)
⇒
\Rightarrow
⇒ 数对只有7*7=49种可能
⇒
\Rightarrow
⇒ 数组前51个数中必出现重复数对
/*
Name: hdu_1005
Copyright:
Author: Topology_l
Date: 27/01/21 11:49
Description:
*/
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int a,b,n;
while(scanf("%d%d%d", &a, &b, &n) && (a != 0 || b != 0 || n != 0)) {
int f[55];
f[1]=f[2]=1;
for(int i=3;i<52;i++){
f[i]=(a*f[i-1]+b*f[i-2])%7;
}
if(n<52){
cout<<f[n]<<endl;
continue;
}
int cst=1,cl=1;
int flag=0;
while(cst<50){
cl=1;
while(cst+cl<51){
if(f[cst]==f[cst+cl]&&f[cst+1]==f[cst+cl+1]){
flag=1;
break;
}
cl++;
}
if(flag) break;
cst++;
}
cout<<f[(n-cst)%cl+cst]<<endl;
}
return 0;
}
1006 Tick and Tick
vj_hdu1006
。。。🙂我以前用的手表真的是一格一格跳的,绝望
这题要连续的搞,离散的精度不够
连续的就得分段求解然后把满足条件的区间长度相加
首先,指针的运动以12h为一周期,故只需计算12x60x60=43200s
这里以指针重合的时候作为划分,秒针每转一圈都会和分针时针分别相遇分针每转一圈也会和时针相遇(即环形跑道上的追及问题),易得两两相遇的时间间隔是固定的
t
=
360
v
1
−
v
2
t=\frac{360}{v_1-v_2}
t=v1−v2360,且在两次相遇的时间点之间两指针距离间隔大于D的时间区间为
[
t
+
D
v
1
−
v
2
,
t
−
360
−
D
v
1
−
v
2
]
[t+\frac{D}{v_1-v_2},t-\frac{360-D}{v_1-v_2}]
[t+v1−v2D,t−v1−v2360−D]。而题目要求的是三组区间(两个指针满足间隔条件的所有区间为一组,共三组)的重合部分的长度和占总时间的百分比。
代码里呢用了三层循环来统计区间重叠长度,说起来如果先 秒分{时秒{时分}}这样套会不会更省时点?三层for总给我种不够优化的感觉…n^3呢…
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define TIME 43200
using namespace std;
int main(){
double d;
while(scanf("%lf",&d)&&d!=-1){
double hm,hs,ms;
hm=120.0/11;
hs=120.0/(120*6-1);
ms=10.0/(60-1);
double thm,ths,tms,sthm,sths,stms,edhm,edhs,edms;
thm = 360*hm;
ths = 360*hs;
tms = 360*ms;
sthm = d*hm;
sths = d*hs;
stms = d*ms;
edhm = (360-d)*hm;
edhs = (360-d)*hs;
edms = (360-d)*ms;
double l,r,ans,i,j,k;
ans=0;
for(i=0;i<=TIME;i=i+thm){
for(j=0;j<=TIME;j=j+ths){
if(j+sths>i+edhm) break;
if(j+edhs<i+sthm) continue;
for(k=0;k<=TIME;k=k+tms){
if(k+stms>j+edhm) break;
if(k+edms<j+sths) continue;
l=max(max(i+sthm,j+sths),k+stms);
r=min(min(i+edhm,j+edhs),k+edms);
if(r>l)
ans+=(r-l);
}
}
}
printf("%.3lf\n",ans*100/TIME);
}
return 0;
}
1007 Quoit Design
任意两点间的最小距离作为环的直径
遍历所有距离O(n2) TLE
《算法导论》33.4章 分治寻找最近点对 O(n log n)
- 对集合P中所有点x坐标,y坐标分别递增排序
- 若 |P|<=3 ,对所有点对进行遍历寻找最近距离;否则,进行下述分治
- 直线x=a将点集P分成数量相等的两个子集PL、PR,且令两个数组中的点保持对x、y坐标值分别有序
- 对PL,PR分别进行递归调用,求出PL内的最近距离 δ L \delta_L δL 和PR内的最近距离 δ R \delta_R δR ,令 δ = m i n ( δ L , δ R ) \delta=min(\delta_L,\delta_R) δ=min(δL,δR),但这个最小距离没有考虑一个点在PL一个点在PR的情况。
- 若存在距离小于 δ \delta δ 且一个点在PL一个点在PR的点对,则点对的两个点一定都在以直线x=a为中心长 2 δ 2\delta 2δ 高 δ \delta δ 的一个矩形内,即在所有x轴坐标在 [ a − δ , a + δ ] [a-\delta,a+\delta] [a−δ,a+δ] 内的点中找距离小于 δ \delta δ 的点对。将该区间内的点依y轴坐标递增排序,若要找与点 p ∈ [ a − δ , a + δ ] p\in[a-\delta,a+\delta] p∈[a−δ,a+δ] 距离小于 δ \delta δ 的点,只需要考虑紧随其后的 7 个点1。对区间 [ a − δ , a + δ ] [a-\delta,a+\delta] [a−δ,a+δ] 内所有点,计算出其到其后7个点的距离,并记录求得的最短距离 δ ′ \delta' δ′
- 返回 m i n ( δ , δ ′ ) min(\delta,\delta') min(δ,δ′)
实现过程中若完全按照该算法分别保存两个排序会出现内存不足的问题,鉴于只有 5 需要y轴排序,因此只在合并时对区间范围内的点按y重新排序
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef struct{
double x;
double y;
}point;
point px[100005];
bool cmpx(point a,point b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmpy(point a,point b){
return a.y<b.y; //递增排序
}
double point_distance(int left,int right){
double dl,dr,dmin,l,h;
if(right-left<3){
dmin = INF;
for(int i=left;i<=right;i++){
for(int j=i+1;j<=right;j++){
l = px[i].x-px[j].x;
h = px[i].y-px[j].y;
l = l*l+h*h;
if(l<dmin) dmin=l;
}
}
return dmin;
}
int len_seg = (right+left)/2;
dl = point_distance(left,len_seg);
dr = point_distance(len_seg+1,right);
dmin = min(dl,dr);
int ll=left,rr=right;
double dm = dmin;
double seg_x = px[len_seg].x;
for(int i=len_seg;i>=left;i--) if(px[i].x < seg_x-dmin){
ll = i+1;break;
}
for(int i=len_seg;i<=right;i++) if(px[i].x >seg_x-dmin){
rr = i-1;break;
}
sort(px+ll,px+rr+1,cmpy);
for(int i=ll;i<=rr;i++){
for(int j=i+1;j<=i+7&&j<=rr;j++){
if(px[j].y-px[i].y >= dmin) break;
l = px[i].x-px[j].x;
h = px[i].y-px[j].y;
l = l*l+h*h;
if(l<dm) dm = l;
}
}
return dm;
}
int main(){
int n;
while(scanf("%d",&n)&&n!=0){
for(int i=0;i<n;i++){
scanf("%lf%lf",&px[i].x,&px[i].y);
}
sort(px,px+n,cmpx);
double ans;
ans = point_distance(0,n-1);
printf("%.2lf\n",sqrt(ans)/2);
}
return 0;
}
1008 Elevator
简单到我以为我看错题了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int main(){
int n;
int now,next,ti;
int up,down,stay;
up = 6;
down = 4;
stay = 5;
while(scanf("%d",&n)&&n!=0){
now = 0;
ti = n*stay;
for(int i=0;i<n;i++){
cin>>next;
if(next > now){
ti += (next-now)*up;
now = next;
}
else if(next < now){
ti += (now-next)*down;
now = next;
}
}
cout<<ti<<endl;
}
return 0;
}
1009 FatMouse’ Trade
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef struct{
int J; //javabeans
int F; //cat food
double ratio;
}food;
bool cmp(food a,food b){
return a.ratio>b.ratio;
}
int main(){
int n,m;
food f[1005];
double cf,a;
while(scanf("%d%d",&m,&n)&&n!=-1&&m!=-1){
for(int i=0;i<n;i++){
cin>>f[i].J>>f[i].F;
f[i].ratio = 1.0*f[i].J/f[i].F;
}
sort(f,f+n,cmp);
cf=0;
for(int i=0;i<n;i++){
if(m<=0) break;
if(m >= f[i].F){
cf += f[i].J;
m -= f[i].F;
}
else{
a = 1.0*m/f[i].F;
cf += f[i].J*a;
break;
}
}
printf("%.3lf\n",cf);
}
return 0;
}
1010 Tempter of the Bone
dfs,要的是满足时间要求的某个可行解,而不是最优解
剪枝:
- 奇偶剪枝,可行解和最短距离奇偶性相同
- 某路径大于时间T就不用考虑了
wa得莫名其妙,放弃了
大佬的ac代码👈
//我的垃圾代码,如果有好心人看出wa点请指点一下我,感谢
//我都已经是照着ac代码改了,依旧wa,疯了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
char map[10][10];
int vis[10][10];
int ne[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int flag;
int stx,sty,edx,edy;
int N,M,T;
void dfs(int x,int y,int len){
int nextx,nexty;
for(int i=0;i<4;i++){
nextx = x+ne[i][0];
nexty = y+ne[i][1];
if(nextx==edx&&nexty==edy&&len+1==T){
flag = 1;
return ;
}
if(len >= T) return ; //剪枝
if(nextx<1||nexty>N||nexty<1||nexty>M||map[nextx][nexty]=='X') continue;
if(vis[nextx][nexty]==0&&map[nextx][nexty]=='.'){
vis[nextx][nexty]=1;
dfs(nextx,nexty,len+1);
if(flag==1) return ;
vis[nextx][nexty]=0; //
}
}
}
int main(){
while(scanf("%d%d%d",&N,&M,&T)){
if(N==0&&M==0&&T==0) break;
memset(vis,0,sizeof(vis));
memset(map,0,sizeof(map));
flag=0;
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
cin>>map[i][j];
if(map[i][j]=='S'){
stx=i;sty=j;
}
if(map[i][j]=='D'){
edx=i;edy=j;
}
}
}
int t=abs(edx-stx)+abs(edy-sty);
if((T-t)%2==1){ //剪枝
cout<<"NO"<<endl;
continue;
}
vis[stx][sty]=1;
dfs(stx,sty,0);
if(flag == 1) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
在矩形 2 δ × δ 2\delta\times\delta 2δ×δ中,对直线x=a左半边正方形区域进行考虑,由于在PL中任意点对的距离大于等于 δ \delta δ,故该区域内至多只能有4个点。因此在矩形 2 δ × δ 2\delta\times\delta 2δ×δ内至多有P中的8个点 ↩︎