| 题目 | 难度 | 知识点 |
|---|---|---|
| A 游游的7的倍数 | ★ | 签到/暴力枚举 |
| B 游游的字母串 | ★ | 枚举 |
| C 游游的水果大礼包 | ★ | 枚举 |
| D 游游的矩阵权值 | ★★ | 数学+推式子 |
总的来说还是不错的,AB一发过,C题先想到了dfs搞一下,后面又想到了DP搞一下,都是会超时的,这个是意料之中的就是想先搞一个暴力再优化,后面发现只需枚举一种包装的个数,另一种基于剩余的计算出来时间为O(n),D关键点在于如何构造,可以发现是数学题故应该是推式子o(1)搞出来,先没取模交一发,然后取模+化简中间漏了一点后面开始修,最后又wa一发是取模中间过程有一点爆LL了,然后又依次的仔细取模过了。果然每次遇到取模题,尤其公式长的时候每次总会中间LL爆,确实该注意。
游游的7的倍数
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],n;
int main(void)
{
string s; cin>>s;
for(int i=0;i<=s.size();i++)//枚举插入的位置
{
string temp;
temp=s.substr(0,i);
for(int j=0;j<=9;j++) //枚举插入的数
{
string temp1=temp;
temp1+=to_string(j);
temp1+=s.substr(i,s.size()-i);
LL flag=stol(temp1);
if(flag%7==0&&flag)
{
cout<<temp1;
return 0;
}
}
}
return 0;
}
游游的字母串
最终情况可以确定,计算每种情况的结果取一个min。由于是环故每一个字母到另一个字母的路径有两条取一个min。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL cnt[N][35];
int main(void)
{
string s; cin>>s;
for(int i=0;i<s.size();i++)
{
int temp=s[i]-'a';
for(int j=0;j<=25;j++)
{
cnt[i][j]=abs(temp-j);
cnt[i][j]=min(abs(temp-j),26-abs(temp-j));
}
}
LL ans=1e18;
for(int i=0;i<=25;i++)
{
LL temp=0;
for(int j=0;j<s.size();j++) temp+=cnt[j][i];
ans=min(ans,temp);
}
cout<<ans;
return 0;
}
游游的水果大礼包
暴力做法:
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef long long int LL;
LL n,m,a,b,f[N][N],ans;
void dfs(int cnt1,int cnt2,int suma,int sumb,LL sum)
{
ans=max(ans,sum);
if(suma==0 || sumb==0) return;
if(suma>=2&&sumb>=1) dfs(cnt1+1,cnt2,suma-2,sumb-1,sum+a);
if(suma>=1&&sumb>=2) dfs(cnt1,cnt2+1,suma-1,sumb-2,sum+b);
}
int main(void)
{
cin>>n>>m>>a>>b;
dfs(0,0,n,m,0);
cout<<ans;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
typedef long long int LL;
LL n,m,a,b,f[N][N],ans;
int main(void)
{
cin>>n>>m>>a>>b;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
f[i][j]=f[i-1][j-1];
if(i-2>=0&&j-1>=0) f[i][j]=max(f[i][j],f[i-2][j-1]+a);
if(i-1>=0&&j-2>=0) f[i][j]=max(f[i][j],f[i-1][j-2]+b);
}
}
cout<<f[n][m];
return 0;
}
正解:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
typedef long long int LL;
LL n,m,a,b,f[N][N],ans;
int main(void)
{
cin>>n>>m>>a>>b;
for(int i=0;i<=1e6;i++)
{
LL sum1=2*i;
LL sum2=i;
if(sum1>n || sum2>m) break;
ans=max(ans,i*a+min(n-sum1,(m-sum2)/2)*b);
}
cout<<ans;
return 0;
}
游游的矩阵权值
可以发现,中间的贡献是4次,边上是3次,角上是2次。 故中间一块用最大的,边上的用次大的,角上用最小的。可以用最小的和最大的退出次大的。
//这个是没考虑mod的式子
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long int LL;
LL n;
int main(void)
{
cin>>n;
LL cnt4=(n-2)*(n-2);//3的总个数
LL sum=(n*n)*(n*n+1)/2;//总的数量
LL temp=n*n-cnt4;//剩余的2-3的个数
LL sum1=sum-(temp)*(temp+1)/2;
LL ans=0;
ans+=sum1*4;
ans+=10*2;
ans+=(sum-sum1-10)*3;
cout<<ans;
return 0;
}
化简后取模的正解:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long int LL;
LL n;
LL qsm(LL a,LL b,LL p)
{
LL sum=1;
while(b)
{
if(b&1) sum=sum*a%p;
a=a*a%p;
b>>=1;
}
return sum%p;
}
int main(void)
{
cin>>n;
n=n%mod;
LL temp1=(n*n)%mod;
LL sum1=2*temp1*(temp1+1)%mod;
LL sum2=(2*n-2)*(4*n-3)%mod;
cout<<(sum1-sum2-10+mod)%mod;
return 0;
}
关于有时候用long long 但是mod的不够还是爆long long的小trick,可以用__int128计算最后再强制的转long long 输出就行了,这样可以极大的避免有时候mod的不足中间爆long long的情况。
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long int LL;
LL n;
LL qsm(LL a,LL b,LL p)
{
LL sum=1;
while(b)
{
if(b&1) sum=sum*a%p;
a=a*a%p;
b>>=1;
}
return sum%p;
}
int main(void)
{
cin>>n;
__int128 temp1=(n*n)%mod;
__int128 sum1=2*temp1*(temp1+1)%mod;
__int128 sum2=(2*n-2)*(4*n-3)%mod;
cout<<(LL)(sum1-sum2-10+mod)%mod;
return 0;
}