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

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

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


T1 Arithmetic of bomb:

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

附上AC代码:

#include 
#include 
#include 
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


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 
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 
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 
#include 
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;
	else
		for (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 
#include 
#include 
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<

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

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

你可能感兴趣的:(TEST)