$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 }
代码戳这里

 

posted @ 2019-10-30 14:21  小叽居biubiu  阅读(209)  评论(0编辑  收藏  举报