A
分别记录纸币剩余数量判断是否能找零,因为数据比较弱所以对于5+5+5的情况没考虑也过了。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a=0,b=0,c=0;
int n;
int flag=1;
while(scanf("%d",&n)!=EOF)
{
if(n==5) a++;
else if(n==10)
{
if(a)
{
a--;
b++;
}
else
{
flag=0;
printf("false");
break;
}
}
else
{
if(a&&b)
{
a--;
b--;
c++;
}
else
{
flag=0;
printf("false");
break;
}
}
}
if(flag) printf("true");
return 0;
}
B
因为一次只能搬一块或者两块砖头,所以对于n块砖头的情况,只需要知道n-1和n-2块砖头有多少种方法,累加即可。dp[i]表示搬i块砖头有多少种方法,递推后输出dp[n]
#include<bits/stdc++.h>
using namespace std;
int maxn=1e5+5;
int main()
{
int dp[maxn];
int n;
while(scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=n;i++)
{
dp[i]+=dp[i-1];
if(i-2>=0)
dp[i]+=dp[i-2];
}
printf("%d",dp[n]);
}
return 0;
}
C
按照题意模拟即可,我给定了循环次数最多num=100。
#include<bits/stdc++.h>
using namespace std;
int maxn=1e5+5;
int main()
{
int num=100;
int n;
int flag=0;
scanf("%d",&n);
while(num--)
{
int temp=0;
while(n)
{
temp+=(n%10)*(n%10);
n/=10;
}
n=temp;
if(temp==1)
{
flag=1;
break;
}
}
if(flag)
printf("YES");
else
printf("NO");
return 0;
}
D
dfs写完发现数据很大,果断超时了,先给出超时代码,后面再改。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int maxn=1e6+5;
const int mod=1e9+7;
int n,a[105],num=1;
ll dfs(int x,int y,int p)
{
ll ans=0;
if(y==num) return 0;
x+=p;
if(x>n) return 0;
// printf("i=%d %d\n",y,x);
if(x==n) return 1;
for(int i=1;i<=a[y+1];i++)
ans=(ans+dfs(x,y+1,i))%mod;
return ans;
}
int main()
{
scanf("%d",&n);
while(scanf("%d",&a[num])!=EOF)
{
num++;
}
ll temp=0;
for(int i=1;i<=a[1];i++)
{
temp=(temp+dfs(0,1,i))%mod;;
}
printf("%lld",temp);
}
E
01背包的裸题,dp[i][j]表示前i个物品背包体积为j时最多能装价值为多少的物品,这里我省去了一维数组直接dp[j]表示体积为j的最大价值,为了保证状态互不影响第二层循环采取倒序,这里根据题意直接物品价值就是其体积。对背包有兴趣的可以百度一下背包九讲,关于如何降维以及为何倒序遍历都有详细解释。
#include<bits/stdc++.h>
using namespace std;
int maxn=1e5+5;
const int mod=1e9+7;
int main()
{
int dp[maxn];
int n,a[maxn];
scanf("%d",&n);
int num=1;
while(scanf("%d",&a[num])!=EOF)
{
//printf("%d\n",a[num]);
num++;
}
// printf("%d\n",num);
memset(dp,0,sizeof(dp));
for(int i=1;i<=num-1;i++)
{
for(int j=n;j>=a[i];j--)
{
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
printf("%d",dp[n]);
return 0;
}
F
这题用到了动态规划的思想,dp[i][j]表示i个筛子掷出j点有多少种可能,那么我们考虑dp[i][j]是如何得到的。我们在掷出第i个筛子的时候会有六种情况,分别对应1~6点,那么得出转移方程
这里得出了每种点数的可能方案数,但是我们求的是概率所以还要求出总的可能数,这个很简单就是6^n。
那么输出即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int maxn=1e4+5;
const int mod=1e9+7;
int quick_pow(int a,int b)
{
int ans=1,base=a;
while(b)
{
if(b&1) ans*=base;
base=base*base;
b>>=1;
}
return ans;
}
int main()
{
double dp[105][605];
int n;
scanf("%d",&n);
for(int i=1;i<=6;i++)
dp[1][i]=1;
for(int i=2;i<=n;i++)
{
for(int j=i;j<=6*i;j++)
{
for(int k=1;k<=6;k++)
if(j>=k)
dp[i][j]+=dp[i-1][j-k];
}
}
int temp=quick_pow(6,n);
for(int i=n;i<=6*n;i++)
{
printf("%d %.6f",i,dp[n][i]/(double)temp);
if(i!=6*n) printf("\n");
}
}