第十周周赛题解
Posted 阿十三
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十周周赛题解相关的知识,希望对你有一定的参考价值。
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 }
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 }
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 }
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 }
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;
以上是关于第十周周赛题解的主要内容,如果未能解决你的问题,请参考以下文章
第六周周赛——AK机会不易得,好好把握题解(出自HDU5650,codeforces 616A,624A,659A,655A,658A)
第六周周赛——AK机会不易得,好好把握题解(出自HDU5650,codeforces 616A,624A,659A,655A,658A)