$NOIP2001$ 题解报告
目录
$Luogu\ P1024$ 一元三次方程求解$(\ √\ )$
$Luogu\ P1025$ 数的划分$(\ √\ )$
$Luogu\ P1026$ 统计单词个数$(\ √\ )$
$Luogu\ P1027$ $Car$的旅行路线$(\ √\ )$
$Luogu\ P2196$ 挖地雷$(\ √\ )$
$Luogu\ P2347$ 砝码称重$(\ √\ )$
$Luogu\ P1024$ 一元三次方程求解
枚举$-100~100$内的每个整数,如果$f(i)=0$,则$i$即为根;如果$f(i)*f(i+1)<0$,则二分求出根。
1 #include<cstdio> 2 double a,b,c,d; 3 double count(double x) 4 { 5 return a*x*x*x+b*x*x+c*x+d; 6 } 7 int main() 8 { 9 double l,r,mid,x1,x2; 10 int tot=0,i; 11 scanf("%lf%lf%lf%lf",&a,&b,&c,&d); 12 for (i=-100;i<100;i++) 13 { 14 l=i; 15 r=i+1; 16 x1=count(l); 17 x2=count(r); 18 if(x1==0) 19 { 20 printf("%.2lf ",l); 21 tot++; 22 } 23 if(x1*x2<0) 24 { 25 while(r-l>=0.001) 26 { 27 mid=(l+r)/2; 28 if(count(mid)*count(r)<=0) 29 l=mid; 30 else 31 r=mid; 32 } 33 printf("%.2lf ",r); 34 tot++; 35 } 36 if (tot==3) 37 break; 38 } 39 return 0; 40 }
$Luogu\ P1025$ 数的划分
直接暴搜,枚举可以分成哪些数,枚举时保证单调递增
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,k; 4 long long ans=0; 5 void dfs(int last,int sum,int K){ 6 if(K==1) {ans++;return;} 7 for(int i=last;i<=sum/K;i++) 8 dfs(i,sum-i,K-1); 9 } 10 int main(){ 11 scanf("%d%d",&n,&k); 12 dfs(1,n,k); 13 printf("%lld\n",ans); 14 return 0; 15 }
$Luogu\ P1026$ 统计单词个数
$DP$,设$f[i][j]$为到第$i$个字符,分成$j$部分的最大答案,预处理$num[l][r]$表示$[l,r]$区间内的单词数
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define g() getchar() 7 #define rg register 8 #define go(i,a,b) for(rg int i=a;i<=b;i++) 9 #define back(i,a,b) for(rg int i=a;i>=b;i--) 10 #define db double 11 #define ll long long 12 #define il inline 13 #define pf printf 14 #define sf scanf 15 #define mem(a,b) memset(a,b,sizeof(a)) 16 using namespace std; 17 int fr(){ 18 int w=0,q=1; 19 char ch=g(); 20 while(ch<'0'||ch>'9'){ 21 if(ch=='-') q=-1; 22 ch=g(); 23 } 24 while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g(); 25 return w*q; 26 } 27 int p,k,n,m,num[202][202],f[202][42]; 28 char s[202],word[7][202]; 29 bool vis[202]; 30 int main(){ 31 //freopen("","r",stdin); 32 //freopen("","w",stdout); 33 p=fr();k=fr(); 34 rg int x=1; 35 go(i,1,p){ 36 sf("%s",s+x); 37 x+=20; 38 } 39 n=p*20;m=fr(); 40 go(i,1,m) sf("%s",word[i]+1); 41 go(i,1,n) go(j,1,n){ 42 mem(vis,0); 43 go(t,1,m){ 44 rg int len=strlen(word[t]+1); 45 go(l,i,j-len+1){ 46 if(vis[l]) continue; 47 bool finish=0; 48 go(r,1,len) 49 if(s[l+r-1]!=word[t][r]) {finish=1;break;} 50 if(!finish) num[i][j]++,vis[l]=1; 51 } 52 } 53 //cout<<"num["<<i<<"]["<<j<<"]="<<num[i][j]<<endl; 54 } 55 go(t,1,k) go(i,1,n) go(j,t-1,i-1) 56 f[i][t]=max(f[i][t],f[j][t-1]+num[j+1][i]); 57 pf("%d\n",f[n][k]); 58 return 0; 59 }
$Luogu\ P1027$ $Car$的旅行路线
用勾股定理预处理出第$4$个点坐标,然后连边,再跑个最短路即可
1 #include<bits/stdc++.h> 2 #define ri register int 3 #define ll long long 4 #define rl register ll 5 #define go(i,a,b) for(ri i=a;i<=b;i++) 6 #define back(i,a,b) for(ri i=a;i>=b;i--) 7 #define g() getchar() 8 #define il inline 9 #define pf printf 10 #define mem(a,b) memset(a,b,sizeof(a)) 11 #define db double 12 using namespace std; 13 il int fr(){ 14 ri w=0,q=1;char ch=g(); 15 while(ch<'0'||ch>'9'){if(ch=='-')q=-1;ch=g();} 16 while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=g(); 17 return w*q; 18 } 19 const int S=102; 20 const int M=80000; 21 const db eps=1e-3; 22 int n,s,t,A,B,T[S],a[4],b[4]; 23 db d[S<<2][S<<2],ans; 24 struct node{ 25 int x,y; 26 }p[S<<2]; 27 il db D(ri u,ri v){ri x=p[u].x-p[v].x,y=p[u].y-p[v].y;return sqrt(x*x+y*y);} 28 il void add(ri id){ 29 db d1=D(id-1,id-2),d2=D(id-1,id-3),d3=D(id-2,id-3); 30 ri x,y;d1*=d1;d2*=d2;d3*=d3; 31 ri x1=p[id-1].x,y1=p[id-1].y; 32 ri x2=p[id-2].x,y2=p[id-2].y; 33 ri x3=p[id-3].x,y3=p[id-3].y; 34 if(fabs(d1+d2-d3)<=eps)x=x2+x3-x1,y=y2+y3-y1; 35 else 36 if(fabs(d1+d3-d2)<=eps)x=x1+x3-x2,y=y1+y3-y2; 37 else x=x1+x2-x3,y=y1+y2-y3; 38 p[id]=(node){x,y};return; 39 } 40 il void build(ri id){ 41 go(i,id-3,id)go(j,i+1,id)d[i][j]=d[j][i]=T[(id>>2)+1]*D(i,j); 42 go(i,id-3,id)go(j,0,id-4)d[i][j]=d[j][i]=t*D(i,j); 43 return; 44 } 45 int main(){ 46 freopen("1.in","r",stdin); 47 freopen("1.out","w",stdout); 48 n=fr(); 49 while(n--){ 50 s=fr();t=fr();A=fr();B=fr();mem(d,0x3f);ans=1000000000; 51 go(i,0,s<<2)d[i][i]=0; 52 go(i,1,s){ 53 ri id=(i-1)<<2; 54 if(i==A)go(j,0,3)a[j]=id+j; 55 if(i==B)go(j,0,3)b[j]=id+j; 56 p[id++]=(node){fr(),fr()}; 57 p[id++]=(node){fr(),fr()}; 58 p[id++]=(node){fr(),fr()}; 59 add(id);T[i]=fr();build(id); 60 } 61 go(k,0,(s<<2)-1)go(i,0,(s<<2)-1)go(j,i+1,(s<<2)-1) 62 d[i][j]=d[j][i]=min(d[i][j],d[i][k]+d[k][j]); 63 go(i,0,3)go(j,0,3)ans=min(ans,d[a[i]][b[j]]); 64 pf("%.1lf\n",ans); 65 } 66 return 0; 67 }
$Luogu\ P2196$ 挖地雷
设$f[i]$表示到$i$最多能挖掉多少地雷。枚举每条边,其实就是枚举两个端点,如果可以更新就更新,并记录这个点是由哪个点更新来的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=22; 4 int n,f[N],before[N],num[N],ans=0,end; 5 bool road[N][N]; 6 void out(int x){ 7 if(before[x]==0) 8 {printf("%d",x);return;} 9 out(before[x]); 10 printf(" %d",x); 11 return; 12 } 13 int main(){ 14 scanf("%d",&n); 15 int i,j,x; 16 for(i=1;i<=n;i++) 17 scanf("%d",&num[i]); 18 for(i=1;i<n;i++) 19 for(j=i+1;j<=n;j++){ 20 scanf("%d",&x); 21 if(x) road[i][j]=road[j][i]=1; 22 } 23 for(i=1;i<=n;i++){ 24 for(j=1;j<=n;j++){ 25 if(road[i][j]&&f[i]<f[j]){ 26 f[i]=f[j]; 27 before[i]=j; 28 } 29 } 30 f[i]+=num[i]; 31 if(f[i]>ans) ans=f[i],end=i; 32 } 33 out(end); 34 printf("\n%d",ans); 35 return 0; 36 }
$Luogu\ P2347$ 砝码称重
有点像个多重背包?就直接暴力枚举即可$QAQ$
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[7],weight[7]={0,1,2,3,5,10,20}; 4 int sum=0; 5 int main(){ 6 int max=0; 7 for(int i=1;i<=6;i++) 8 {scanf("%d",&a[i]);max+=a[i]*weight[i];} 9 for(int j=max;j>=1;j--) 10 { 11 int w=j; 12 for(int i=6;i>=1;i--) 13 { 14 for(int k=a[i];k>=1;k--) 15 {w-=weight[i]; 16 if(w==0) {sum++;break;} 17 if(w>0) continue; 18 if(w<0) w+=weight[i];} 19 } 20 } 21 printf("Total=%d",sum); 22 return 0; 23 }