【TEST】2017百度之星程序设计大赛

来源:互联网 发布:linux 查看连接的ip 编辑:程序博客网 时间:2024/06/06 02:41

Pre:其实这并不是一场考试,使我们这周的作业,但还是我自认为还是挺难的。对于那些觉得这些题目太水而不想做的大佬我只能表示orz了……

注:HDU上有原题,有兴趣的同学可以去AK一下。


T1 Arithmetic of bomb:

一道超级水的模拟题,因为展开次数不超过10……直接用字符串模拟就好了,注意大数取模。

附上AC代码:

#include <cstdio>#include <string>#include <cstring>using namespace std;const int MOD=1e9+7;int t,len;long long ans;char s[1010];string s1,s2;int main(void){scanf("%d",&t);while (t--){scanf("%s",s+1),len=strlen(s+1),s2="";for (int i=1; i<=len; )if (s[i]=='('){s1="";int j=i+1;for (;isdigit(s[j]);++j) s1+=s[j];for (;!isdigit(s[j]); ++j);int p=s[j]-'0';for (int k=1; k<=p; ++k) s2+=s1;i=j+2;}else s2+=s[i++];ans=0;for (int i=0; i<s2.size(); ++i) ans=ans*10+s2[i]-'0',ans%=MOD;printf("%lld\n",ans);}return 0;}


t2 Arithmetic of bomb II:

这看上去和上一题差不多,也是一道模拟题,但不知道为什么没人过……于是就先挖个坑,等有大佬过了这题并把我教会了再来填坑吧。


t3 Pokémon GO:

这是一道比较操作的递推题……

首先不难发现最少步数为n*2,于是题目变成求从任意节点开始用n*2的步数走完所有节点的方案数。

我们令b[i]表示从第i列走完所有节点并回到第i列的方案书。显然b[i]=2^(i-1)

我们再令a[i]表示总共有i列,从四个角中任意一个出发走完所有节点的方案数。(下面的解法以左上角为例)

先给出递推公式:a[i]=b[i]+2*a[-1]+4*a[i-2]

证明:把两个+去掉,分解公式为三个部分

  1. 从这个角出发,走完所有节点然后回到这个角的正下方,有b[i]种方案
  2. 从这个角出发,先走到这个角的正下方,然后有两种方案走到第2列,所以方案数为2*a[i-1]
  3. 从这个角出发,用走对角线的方式走完前两列,停在第二列,有两种方案,然后第二列的每个节点有两种可能走到第三列,所以方案数为4*a[i-2]
显然当n>1的时候有四个角,初始化sum=4*a[n],n=1的情况特判掉就行了。

然后考虑3起点在2~n-1列,显然可以先用b的方式走掉一边,然后用a的方式走掉另一边。

递推公式直接推出就行了(设左边有l列,右边有r列):sum+=2*(4*b[l]*a[r]+4*b[r]*a[l])

a和b数组可以预处理出来,然后这题就是O(n)的时间复杂度了,直接A掉即可。

附上AC代码:

#include <cstdio>using namespace std;const int N=1e4+10,p=1e9+7;long long a[N],b[N],t,n,ans;inline void build(void){b[1]=1,a[1]=1,a[2]=6;;for (int i=2; i<=N; ++i) b[i]=b[i-1]*2%p;for (int i=3; i<=N; ++i) a[i]=(b[i]+2*a[i-1]+4*a[i-2])%p;}int main(void){build(),scanf("%d",&t);while (t--){scanf("%d",&n);if (n==1){printf("2\n");continue;}ans=4*a[n]%p;for (int i=2; i<=n-1; ++i) ans=(8*(b[i-1]*a[n-i]%p+a[i-1]*b[n-i]%p)%p+ans)%p;printf("%lld\n",ans);}return 0;}

t4 Pokémon GO II:

一道思想题,不知道为什么各种大佬都说这题是一道平面几何题,蒟蒻吓得瑟瑟发抖……

显然相交的方式只有三种:里面相交、外面相交和平行相交,直接O(n)判断就好了。

不知怎么的,HDU上面的数据特别水,第三种平行相交我并没有判断过,但是还是A掉了这题……

代码也不想改了,有兴趣的同学自己改吧……

附上AC代码:

#include <cstdio>using namespace std;const int N=1e6+10;int t,n,a[N],b;int main(void){scanf("%d",&t);while (t--){scanf("%d",&n),b=0;for (int i=1; i<=n; ++i){scanf("%d",&a[i]);if (i>3&&!b&&a[i-1]<=a[i-3]&&a[i-2]<=a[i]) printf("%d\n",i),b=1;if (i>5&&!b&&a[i-1]<=a[i-3]&&a[i-4]<=a[i-2]&&a[i]+a[i-4]>=a[i-2]&&a[i-1]+a[i-5]>=a[i-3]) printf("%d\n",i),b=1;}if (!b) puts("Catch you");}return 0;}

t5 Valley Numer:

题意非常明确:数位DP题。

记忆化搜索大法好,比那些DP方程不知道好理解到哪里去了。

其实这题还是挺简单的,就是要考虑的细节比较多,稍微细心一点就好了。

附上AC代码:

#include <cstdio>#include <cstring>using namespace std;const int N=110,p=1e9+7;long long t,f[N][11][2],n,a[N];char s[N];inline long long so(int pos,int status,int pre,int limit){if (pos<1) return 1;if (!limit&&~f[pos][pre][status]) return f[pos][pre][status];int end=limit?a[pos]:9;long long ans=0;if (status) for (int i=pre; i<=end; ++i) ans=(ans+so(pos-1,status,i,limit&&i==end))%p;elsefor (int i=0; i<=end;++i)if (i>pre) ans=(ans+so(pos-1,1,i,limit&&i==end))%p;else if (!i&&pre==10) ans=(ans+so(pos-1,0,10,limit&&i==end))%p;else ans=(ans+so(pos-1,0,i,limit&&i==end))%p;if (!limit) f[pos][pre][status]=ans;return ans;}int main(void){scanf("%lld",&t),memset(f,-1,sizeof f);while (t--){scanf("%s",s+1),n=strlen(s+1);for (int i=1; i<=n; ++i) a[n-i+1]=s[i]-'0';printf("%lld\n",so(n,0,10,1)-1);}return 0;}

t6 Valley Numer II:

数据范围中k<=15,想到了状压DP。

显然我们要压的是题目中给出的高点,然后枚举低点和两个高点,保证两个高点不在当前枚举的状态里的前提下更新DP数组。

突然发现DP数组可以用滚动的方式来节省空间,因为当前低点的状态只和它前一个低点的状态有关。

于是这题就很轻松的被A掉啦。

p.s.orz教主大佬,他说他并不像写DP,于是就用网络流A掉了这题,怎么做到的QwQ

附上AC代码:

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int N=31;int n,m,k,map[N][N],x,y,a[N],f[N][1<<16],ans,now,t;bool b[N];int main(void){scanf("%d",&t);while (t--){scanf("%d%d%d",&n,&m,&k);memset(f,0,sizeof f),memset(b,0,sizeof b),memset(map,0,sizeof map);for (int i=1; i<=m; ++i) scanf("%d%d",&x,&y),map[x][y]=map[y][x]=1;for (int i=1; i<=k; ++i) scanf("%d",a+i),b[a[i]]=1;for (int i=1; i<=n; ++i){if (b[i]) continue;now^=1,memcpy(f[now],f[now^1],sizeof f[now]);for (int sub=0; sub<=(1<<k)-1; ++sub)for (int j=1; j<=k; ++j){if ((sub&(1<<j-1))||!map[i][a[j]]) continue;for (int t=j+1; t<=k; ++t){if ((sub&(1<<t-1))||!map[i][a[t]]) continue;f[now][sub|(1<<j-1)|(1<<t-1)]=max(f[now][sub|(1<<j-1)|(1<<t-1)],f[now^1][sub]+1);}}}ans=0;for (int i=0; i<=(1<<k)-1; ++i) ans=max(ans,f[now][i]);printf("%d\n",ans);}return 0;}

End:大概是许多大佬不屑于做这种水题吧,我这个蒟蒻竟然排到了rk5……

大佬大概都去做各种神题了吧,只有我这个蒟蒻留在这里淦这些大佬所谓的水题吧……