2021卓见杯第三届CCPC河南省省赛所有题超详细题解附加榜单真题解析,简单代码+详细注释+思想,要看的,补题的速速点进来 2021 10.30
Posted WAWA源
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021卓见杯第三届CCPC河南省省赛所有题超详细题解附加榜单真题解析,简单代码+详细注释+思想,要看的,补题的速速点进来 2021 10.30相关的知识,希望对你有一定的参考价值。
本人现在比较菜,所以难免出现错误,文章中有不太恰当地方,还请大家指正。
是否因为出题人的简短题解而发愁?,是否看不懂出题人的变态模板标程?是否因为自己是小白而苦恼?来看这片文章,帮助你解决这些问题
题目已经全部补完,1004不想看了,其他均有题解,如果有收获请点个赞再走吧…
1001.收集金币
题目链接
算法:动态规划
状态dp思路:
f[i][0]
表示前i
个操作中一直没有跳的最大金币数量
f[i][1]
表示前i
个操作中已经跳过或者现在跳的最大金币数量
状态转移:
f[i][0]很简单只有一种状态
f[i][0]=f[i-1][0]+x
f[i][1]有两种状态可以转移过来
1.f[i][1]
可以是第i
个操作跳过即前i-1
没有跳过即f[i-1][0]
2.前i-1
已经跳过了,现在不需要跳过f[i-1][1]-x
所以
f[i][1]=max(f[i-1][0],max(f[i-1][1]-x,0ll))
最终状态
f[n][0]
从头到尾一次都没跳过
f[n][1]
只跳过一次的最大值
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010;
typedef long long LL;
LL f[N][2];
int main()
{
int T,n,x;
string s;
cin>>T;
while(T--)
{
memset(f,0,sizeof f);
f[0][0]=0;
f[0][1]=-1e5;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s>>x;
if(s=="LOST")
{
f[i][1]=max(f[i-1][0],max(0ll,f[i-1][1]-x));
f[i][0]=max(0ll,f[i-1][0]-x);
}
else
{
f[i][0]=f[i-1][0]+x;
f[i][1]=f[i-1][1]+x;
}
}
cout<<max(f[n][0],f[n][1])<<endl;
}
}
1002.使用技能
题目链接
算法:乘法逆元+快速幂
题意:这道题题目意思比较难懂,代码比较简单。由题意知序列的总数量是m^n
的,我们需要先计算出所有序列的价值和,再除以序列总数量。
因为序列存在排序状态,因此每个序列都不一样。我们直接枚举释放x
次技能的总数量,再加起来较为简便,首先需要从n
个序列中挑选出x
个位置即C(n,x)
然后乘以m
个技能,因为每个技能都可以,在把其他位置填满即可即(m-1)^(n-x)
最后乘以每个价值x^2
公式为C(n,x)*m*(m-1)^(n-x)*x^2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
const int mod = 1e9+7;
const int maxn = 100000;
LL n,m;
LL jc[N],ni[N];
LL qmi(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
LL C(LL n,LL m)
{
return jc[n]*ni[m]%mod*ni[n-m]%mod;
}
int main()
{
int T;
cin>>T;
jc[0]=1;
for(int i=1;i<=maxn;i++)jc[i]=jc[i-1]*i%mod;
ni[maxn]=qmi(jc[maxn],mod-2);
for(int i=maxn-1;i>=0;i--)ni[i]=ni[i+1]*(i+1)%mod;
while(T--)
{
cin>>n>>m;
LL res=0;
for(int i=1;i<=n;i++)
{
res=res+C(n,i)*i%mod*i%mod*m%mod*qmi(m-1,n-i)%mod;
res%=mod;
}
res=res*qmi(qmi(m,n),mod-2)%mod;
cout<<res<<endl;
}
}
1003.欢度佳节
题目链接
算法:位运算+暴搜
思路:题目求占领的最大方块,所以筛子数值就假设每次一定是6,仔细看题,糖果库存大于某个格子的数值,且这个格子与你占领的格子相邻,那么你可以选择占领这个格子这里的大于容易理所应当的看成大于等于,所以每个格子需要的掷投数量就是a[i]=a[i]/6+1
本题需要先把输入的一维数据转化为二维,用方位数组dx【】,dy【】
进行每个方位判断,之后根据位运算,再把二维转化为一维。
因为是17个格子,所以2^17不会超时,可以暴力来做,用二进制枚举每一个状态,是1则表示会到这个格子上,0则反之,每个二进制数字再进行判断是否符合题目要求,如果符合找出二进制中1的个数,每次更新,求最大值即可。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 17;
int x[]={1,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,5};
int y[]={1,2,4,5,2,3,4,2,3,4,2,3,4,1,2,4,5};
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
int a[20],mp[20][20];
bool st[20];
int n;
int arrive=0,sum=0;
void dfs(int x,int y,int state)
{
//这里的arrive用于判断路径的连通性和进行判重,不再走原来走过的路
int id=mp[x][y];
if((id==-1)||(state>>id)%2==0||(arrive>>id)%2==1)return ;
sum+=a[id];
arrive|=1<<id;
for(int i=0;i<4;i++)
{
dfs(x+dx[i],y+dy[i],state);
}
}
int main()
{
memset(mp,-1,sizeof mp);
//二维转化为一维为了进行位运算判断
for(int i=0,cnt=0;i<N;i++)
mp[x[i]][y[i]]=cnt++;
int T;
cin>>T;
while(T--)
{
for(int i=0;i<N;i++)
{
cin>>a[i];
a[i]=a[i]/6+1;
}
cin>>n;
int res=0;
//枚举每种状态
for(int state=0;state<1<<N;state++)
{
//第13个数字是出发点,如果状态中没有则直接continue
if((state>>13)%2==0)continue;
arrive=0,sum=0;
//这里的arrive用于判断路径的连通性和进行判重,不再走原来走过的路
dfs(x[13],y[13],state);
if(arrive==state&&sum<=n)
{
res=max(res,__builtin_popcount(state));
}
}
cout<<res<<endl;
}
}
1004. 五个小时卷积神经网络从入门到入土
题目链接
题太长了不想写了。。。。直接把标程代码搬过来了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int N = 1e3+7;
template <typename T, typename H>
inline T qpow(const T &a, const H &p, const int &mo = MOD) {
long long res = 1, x = a;
for (H i = p; i; i >>= 1, x = x*x%mo)
if (i&1) res = res*x%mo;
return static_cast<T>(res);
}
int n, m;
char s[N];
const ll inv = qpow(4, MOD-2);
signed main() {
int T = 1;
scanf("%d", &T);
while (T--){
scanf("%d%d", &n, &m);
ll ans = 0, sumw = 0;
for (int i = 0; i < 3; ++i)
for (int j = 0, w; j < 3; ++j) {
scanf("%d", &w);
sumw += w;
}
for (int i = 0; i < n; ++i) {
scanf("%s", s);
for (int j = 0; j < n; ++j)
ans += s[j] == '1';
}
ans = ans*qpow(sumw*inv%MOD, m)%MOD;
printf("%lld\\n", ans);
}
return 0;
}
1005.闯关游戏
题目链接
算法:01背包+贪心
思路:这道题比较巧妙,看起来像分组背包,但其实不是,先根据贪心的思路进行判断,把一个空间更小的数放进背包,在把差值跑一边01背包,非常巧妙
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=6010;
int a[N],b[N],c[N],d[N];
int f[N];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
memset(f,0,sizeof f);
int res=0,now=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i]>>d[i];
for(int i=1;i<=n;i++)
{
if(a[i]>c[i])
{
swap(a[i],c[i]);
swap(b[i],d[i]);
}
if(b[i]>d[i])
{
d[i]=b[i];
}
if(m<a[i])break;
m-=a[i];
now+=b[i];
c[i]-=a[i];
d[i]-=b[i];
for(int j=m;j>=c[i];j--)
{
f[j]=max(f[j],f[j-c[i]]+d[i]);
}
res=max(res,now+f[m]);
}
cout<<res<<endl;
}
}
1006.军训
题目链接
算法:打表+玄学盲猜+数学+注意卡常
本题解摘自:_ sky123 _
原文链接:https://sky123.blog.csdn.net/article/details/121102090
通过小范围打表可知,f(n)
增长的非常缓慢,因此可以猜出当 n ≤ 109
时f(n)
不会很大(实际上不会超过17
)。
设最优解第一个矩阵长宽分别为 x
和 x + a
;第二个矩阵长宽分别为y
和 y + b
,则有如下方程:
x ( x + a ) + y ( y + b ) = n
其中 a + b = f ( n )
。
由于f(n)
不会很大,因此首先枚举f(n)
,然后枚举 a
进而得到 b
。之后枚举 x
,由于 x
在方程中的次数为2
,因此枚举范围为O(
n
\\sqrt{n}
n) 。
在 a,b,x
的值确定之后,原方程可以转化为关于y
的一个二次方程。利用求根公式 O(1)
判断该方程是否有合法的整数解即可确定有无对应方案。
因为枚举 f ( n )
,a
最坏为90
次,因此最终复杂度为O(90T
n
\\sqrt{n}
n) 。
比较卡常,需要特判几个f(n)
比较大的 n
。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T, n;
inline bool check(int d) {
for (int a = 0; a <= d / 2; a++)
第十三届蓝桥杯省赛C++B组 真题题解(详细讲解+代码分析)看这篇就够了~~~
第十三届蓝桥杯省赛C++B组 真题题解(详细讲解+代码分析)看这篇就够了~~~
《蓝桥杯真题》:2021单片机省赛第二场暨第十三届蓝桥杯赛前模拟试题