首页 > 代码库 > 第十周周赛题解

第十周周赛题解

A题:

二分题目,具体二分公式看我代码吧(ーー゛)

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define maxa 20100
 6 using namespace std;
 7 int a[maxa],l[maxa],r[maxa],n;
 8 bool comp(int p)
 9 {
10     int x= a[1],y= p-a[1],i;
11     memset(l,0,sizeof(l));
12     memset(r,0,sizeof(r));
13     l[1] =x;
14     r[1] = 0;
15     for(i=2; i<=n; ++i)
16     {
17         if(i%2==0)
18         {
19             l[i] = min(x-l[i-1],a[i]);
20             r[i] =a[i]-l[i];
21         }
22         else
23         {
24             r[i] = min(y-r[i-1],a[i]);
25             l[i] = a[i]-r[i];
26         }
27     }
28     return l[n]==0;
29 }
30 int main()
31 {
32     int i;
33     //freopen("E:/造数据/in1_test.in","r",stdin);
34     //freopen("E:/造数据/in1_test.out","w",stdout);
35     while(scanf("%d",&n)!=EOF)
36     {
37         for(i=1; i<=n; ++i)
38             scanf("%d",&(a[i]));
39         int L=0,R=0;
40         for(i=1; i<n; ++i)
41         {
42             L = max(L,a[i]+a[i+1]);
43             R = max(R,3*a[i]);
44         }
45         R =max(R,3*a[n]);
46         L = max(L,a[1]+a[n]);
47         if(n%2==1)
48         {
49             while(L<=R)
50             {
51                 int mid =(L+R)/2;
52                 if(comp(mid)==true)
53                 {
54                     R =mid-1;
55                 }
56                 else
57                     L = mid+1;
58             }
59         }
60         printf("%d\n",L);
61     }
62     return 0;
63 }
View Code

B题:

topo排序然后简单dp,或者直接爆搜加个记忆化...(如果是记忆化,记得不要用0来表示未访问的点QwQ)

技术分享
 1 #include <stdio.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int MAXN=1e5+5, MD=10007;
 5 int in[MAXN], deg[MAXN], to[MAXN][10], K[MAXN], N;
 6 int p[MAXN], M, f[MAXN], ans;
 7 int read()
 8 {
 9     int r=0,c=getchar();
10     while(c<0||9<c)
11         c=getchar();
12     while(0<=c&&c<=9)
13         r=r*10+c-0, c=getchar();
14     return r;
15 }
16 int main()
17 {
18     scanf("%d", &N);
19     for(int i=1; i<=N; ++i)
20     {
21         K[i]=read();
22         for(int j=0; j<K[i]; ++j)
23             in[to[i][j]=read()]++;
24     }
25     for(int i=1; i<=N; ++i)
26         if(!in[i])
27             f[p[M++]=i]=1;
28     for(int i=0; i<M; ++i)
29     {
30         int u=p[i];
31         for(int j=0; j<K[u]; ++j)
32         {
33             int v=to[u][j];
34             if(!(--in[v]))
35                 p[M++]=v;
36         }
37     }
38     for(int i=0; i<M; ++i)
39     {
40         int u=p[i];
41         for(int j=0; j<K[u]; ++j)
42         {
43             int v=to[u][j];
44             f[v]=(f[v]+f[u])%MD;
45         }
46         if(!K[u])
47             ans=(ans+f[u])%MD;
48     }
49     printf("%d\n", ans);
50     return 0;
51 }
View Code

C题:

这是一道数学题(ーー゛)

题意:已知技术分享T

 

积化和差公式推一下即可。最后枚举T

 

技术分享

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 using namespace std;
 5 long long n;
 6 int i,t;
 7 long double p,dt=1e9,s,ds;
 8 int main()
 9 {
10     scanf("%lld%Lf",&n,&p);
11     for(i=1; i<68; i++)
12     {
13         s=(cos(i-0.5)-cos(i+n-0.5))/sin(0.5)/2;
14         ds=abs(s-p);
15         if(ds<dt)
16         {
17             t=i;
18             dt=ds;
19         };
20     }
21     printf("%d",t);
22 }
View Code

D题:

区间DP题目

状态只有2种:从左边拿和从右边拿。

假设当前状态a1,a2,a3,a4,a5,如果第一个人选最左边的,则问题转化为四个数a2,a3,a4,a5,然后第二个人先选,由于题目说第二个人方案也最优,所以选的也是最优方案,即f[i+1][j];先选右边同理。

f[i][j]表示i~j区间段第一个人选的最优方案。

所以dp转移方程为:f[i][j]=max{ sum[i+1][j]-f[i+1][j]+ai,sum[i][j-1]-f[i][j-1]+aj }

sum[i][j]其实就等于sum[1][j]-sum[1][i-1],于是我们用一个s数组,s[i]表示前1~i个数的和,就好了。

所以dp转移方程也可写成f[i][j]=max((s[j]-s[i-1])-f[i+1][j],(s[j]-s[i-1])-f[i][j-1]);

根据dp转移方程我们可以发现,要得到状态f[i][j],必须要得到状态f[i+1][j]和f[i][j-1]。

技术分享
 1 #include<stdio.h>
 2 #include<algorithm>
 3 using namespace std;
 4 int n,i,j;
 5 int a[101];//存数
 6 int f[101][101];
 7 //f[i][j]表示取i~j这个区间段player1最高得分
 8 int s[101];//s[i]表示a[1]~a[i]的和
 9 int main()
10 {
11     //freopen("E:/造数据/in2_test.in","r",stdin);
12     //freopen("E:/造数据/in2_test.out","w",stdout);
13     while(scanf("%d",&n)!=EOF)
14     {
15         for (i=1; i<=n; i++)
16         {
17             scanf("%d",&a[i]);//读入 s
18             s[i]=s[i-1]+a[i];//求和
19             f[i][i]=a[i];//初始化
20         }
21         //表示a[i]~a[j]的和的方法:s[j]-s[i-1]
22         for (i=n-1; i>=1; i--)
23             for (j=i+1; j<=n; j++)
24                 f[i][j]=max((s[j]-s[i-1])-f[i+1][j],
25                             (s[j]-s[i-1])-f[i][j-1]);
26         printf("%d %d\n",f[1][n],s[n]-f[1][n]);
27     }
28     return 0;
29 }
View Code

E题:

这真是水题(ーー゛)

主要是找规律:

如果有一段夹在1中间的0就要多翻两次,说明只要找有多少段夹在1中的0就行了,而还有特殊情况就是没被1夹住的0,

没被夹住的0,也直接翻一次就行了。

技术分享
 1 #include <stdio.h>
 2 #include <string.h>
 3 int main()
 4 {
 5     int sum=0;
 6     char a[50000];
 7     //freopen("E:/creat/in3_test.in","r",stdin);
 8     //freopen("E:/creat/in3_test.out","w",stdout);
 9     while(scanf("%s",a)!=EOF)
10     {
11         sum=0;
12         int i=0,j;
13         for(; i<strlen(a); i++)
14         {
15             if(a[i]==0)
16             {
17                 if(a[i-1]==1)sum++;//判断0前面是否是1
18                 for(; i<strlen(a); i++) //判断是否有被1夹住
19                     if(a[i]==1) //判断0后面是否是1
20                     {
21                         i--;    //因为外循环回把i加1,这样会少判断一个,所以先减一
22                         break;
23                     }
24                 sum++;//这个非常重要,不管是什么情况都包括了
25             }
26             else //如果是1的情况,就像往后找0
27             {
28                 for(; i<strlen(a); i++)
29                     if(a[i]==0)
30                     {
31                         i--;
32                         break;
33                     }
34             }
35         }
36         printf("%d\n",sum);
37     }
38     return 0;
39 }
复杂度过高的代码

贴上学长的代码:

技术分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 char s[1000005];
 4 int main()
 5 {
 6     while(gets(s))
 7     {
 8         int k = 0;
 9         int i;
10         for(i=1;s[i];i++)
11         {
12             if(s[i] != s[i-1]) {
13                 k++;
14             }
15         }
16         if(s[i-1] == 0) k++;
17         printf("%d\n",k);
18     }
19 
20     return 0;
学长的代码

 

第十周周赛题解