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
这看上去和上一题差不多,也是一道模拟题,但不知道为什么没人过……于是就先挖个坑,等有大佬过了这题并把我教会了再来填坑吧。
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]
证明:把两个+去掉,分解公式为三个部分
然后考虑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;
}
数据范围中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<
大佬大概都去做各种神题了吧,只有我这个蒟蒻留在这里淦这些大佬所谓的水题吧……