1.激光炸弹
题意:给一个R×R的炸弹,和n个宝藏的坐标和价值,求可以炸掉的最大价值
思路:建立一个二维数组的前缀和,s[i][j]代表者
所以s[i][j]=s[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
对于半径为r的正方形的价值为,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r];
核心代码`
for(int i=1;i<=5001;i++)
{
for(int j=1;j<=5001;j++)
{
qzh[i][j]=qzh[i][j]+qzh[i-1][j]+qzh[i][j-1]-qzh[i-1][j-1];
}
}
int ans=0;
for(int i=r;i<=5001;i++)
{
for(int j=r;j<=5001;j++)
{
ans=max(ans,qzh[i][j]-qzh[i-r][j]-qzh[i][j-r]+qzh[i-r][j-r]);
}
}
2.约数之和
题目:求A^B的所有约数和是多少
思路:利用唯一分解定理和约数和定理分治递归求解
pn代表p的n次方
计算1+p+p1+······+pn可分为两类
n为奇数,有偶数项
n为偶数,有奇数项,当独拿出最后一项,然后按偶数项处理
核心代码
ll solve(ll p,ll c)
{
if(c==0)return 1;
if(c&1)
{
return ((1+ksm(p,(c+1)>>1))*solve(p,(c-1)>>1))%mod;
}
else
{
return ((1+ksm(p,c>>1))*solve(p,(c>>1)-1)+ksm(p,c))%mod;
}
}
3.石子合并
题意:给你n堆石子,让你合并到只有一堆石子,每次合并两堆石子的的代价是两队的石子的权值之和,求最小和并代价
思路:区间dp模板题,dp[i][j]=min(dp[i][k]+dp[k+1][j]+s[j]-s[i-1])
核心代码
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int r=i+len-1;
dp[i][r]=0x3f3f3f3f;
for(int j=i;j<r;j++)
{
dp[i][r]=min(dp[i][r],dp[i][j]+dp[j+1][r]+s[r]-s[i-1]);
}
}
}
4.启示录
题意:有三个连续的6的是魔鬼数,如666,1666,6663,16666,6660666,求第x个魔鬼数
思路:数位dp+二分+记忆化搜索
核心代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll dp[30][30];
ll num[30];
ll dfs(ll pos,ll limit,ll state)
{
if(pos==-1)
{
if(state==3)return 1;
else return 0;
}
if(!limit&&dp[pos][state]!=-1)return dp[pos][state];
ll up=limit?num[pos]:9;
ll sum=0;
for(ll i=0; i<=up; i++)
{
ll nextState=0;
if(state==3)
{
nextState=3;
}
else if(state==2&&i==6)
{
nextState=3;
}
else if(state==1&&i==6)
{
nextState=2;
}
else if(state==0&&i==6)
{
nextState=1;
}
sum+=dfs(pos-1,limit&&i==up,nextState);
}
if(!limit)dp[pos][state]=sum;
return sum;
}
ll solve(ll x)
{
int cnt=0;
while(x)
{
num[cnt++]=x%10;
x/=10;
}
return dfs(cnt-1,1,0);
}
int main()
{
memset(dp,-1,sizeof(dp));
int t;
cin>>t;
while(t--)
{
ll x;
cin>>x;
ll l=1,r=1e10,ans=1,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(solve(mid)>=x)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
cout<<ans<<endl;
}
return 0;
}