题解:
矩阵转换,坐标变一下二维前缀和,枚举中心,更新\(ans\)最大值
坐标关系:
\(X'=X+Y-1\);
\(Y'=N-(X-Y)\);
\(code\):
#include<cstdio>
#include<ctype.h>
#include<vector>
#include<string.h>
#include<algorithm>
#define ll long long
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
bool flag=0;
while(!isdigit(tt=gc())&&tt!='-');
tt=='-'?(flag=1,x=0):(x=tt-'0');
while(isdigit(tt=gc())) x=x*10+tt-'0';
if(flag) x=-x;
}
const int maxn=2002;
struct node{
int x,y;
inline node(int a=0,int b=0)
{x=a,y=b;}
}a[maxn*maxn];
int n,k,tot;
int m[maxn<<1][maxn<<1];
int w[maxn<<1][maxn<<1];
int main()
{
read(n),read(k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;
read(x);
m[i+j-1][n-(i-j)]=x;
a[++tot]=node(i+j-1,n-(i-j));
}
for(int i=1;i<=n<<1;i++)
for(int j=1;j<=n<<1;j++)
w[i][j]=w[i-1][j]+w[i][j-1]-w[i-1][j-1]+m[i][j];
// for(int i=1;i<=n<<1;i++,putchar(10))
// for(int j=1;j<=n<<1;j++)
// printf("%d ",m[i][j]);
// putchar(10);
// for(int i=1;i<=n<<1;i++,putchar(10))
// for(int j=1;j<=n<<1;j++)
// printf("%d ",w[i][j]);
int ans=0;
for(int i=1;i<=tot;i++)
{
int x1,x2,y1,y2;
x1=max(a[i].x-k+1,1);
x2=min(a[i].x+k-1,(n<<1)-1);
y1=max(a[i].y-k+1,1);
y2=min(a[i].y+k-1,(n<<1)-1);
ans=max(ans,w[x2][y2]-w[x1-1][y2]-w[x2][y1-1]+w[x1-1][y1-1]);
}
printf("%d",ans);
}
题解:
下放边权,统计这条边贡献,即从上面到下面点的次数,乘法原理,\(ans=\sum sz[x]*(n-sz[x])*w[x]\),记住在乘法处需要类型转换!!!切记切记,改悔改悔
\(code:\)
#include<cstdio>
#include<ctype.h>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
bool flag=0;
while(!isdigit(tt=gc())&&tt!='-');
tt=='-'?(flag=1,x=0):(x=tt-'0');
while(isdigit(tt=gc())) x=x*10+tt-'0';
if(flag) x=-x;
}
const int maxn=1e5+2;
ll ans;
ll n,m,sz[maxn],w[maxn];
vector<ll>G[maxn];
void dfs(ll x)
{
sz[x]++;
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i];
dfs(p);sz[x]+=sz[p];
}
ans+=sz[x]*(n-sz[x])*w[x];
}
int main()
{
read(n);
for(int i=1;i<n;i++)
{
ll x,y;
read(x),read(y);
G[x].push_back(i+1);
w[i+1]=y;
}
dfs(1);
printf("%lld\n",ans);
read(m);
while(m--)
{
int x,y;
read(x),read(y);
ans-=sz[x]*(n-sz[x])*w[x];
w[x]=y;
ans+=sz[x]*(n-sz[x])*w[x];
printf("%lld\n",ans);
}
}
题解:
棋盘\(DP\),设定状态为\(F[i][j][k]\),表示到达\((i,j)\)这点用了\(k\)个技能所消耗最小值,不用技能就向右边或下面转移,用技能就用\(dfs\)直接跑到目标点
\(code:\)
#include<cstdio>
#include<ctype.h>
#include<vector>
#include<string.h>
#include<algorithm>
#define ll long long
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
bool flag=0;
while(!isdigit(tt=gc())&&tt!='-');
tt=='-'?(flag=1,x=0):(x=tt-'0');
while(isdigit(tt=gc())) x=x*10+tt-'0';
if(flag) x=-x;
}
const int maxn=502;
int n,m,t,k,h,atk,w[maxn][maxn];
int f[maxn][maxn][10];
int cal(int x,int y,int z){return (h-1)/z*w[x][y];}
void merge(int &x,int y){x=min(x,y);}
void dfs(int x,int y,int num,int step,int atkk,int val)
{
if(step) val+=cal(x,y,atkk);
if(!(step^k)) {merge(f[x][y][num+1],val);return;}
if(x^n) dfs(x+1,y,num,step+1,atkk+w[x+1][y],val);
if(y^m) dfs(x,y+1,num,step+1,atkk+w[x][y+1],val);
}
int main()
{
read(n),read(m),read(t),read(k),read(h),read(atk);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) read(w[i][j]);
memset(f,30,sizeof(f));f[1][1][0]=0;
for(int num=0;num<=t;num++)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(i^n) merge(f[i+1][j][num],f[i][j][num]+cal(i+1,j,atk));
if(j^m) merge(f[i][j+1][num],f[i][j][num]+cal(i,j+1,atk));
if(num^t) dfs(i,j,num,0,atk,f[i][j][num]);
}
printf("%d",f[n][m][t]);
}