A - Pay to Win
代码看起来长,但大部分都是复制粘贴的。
核心思路:逆向思维
从0到n有很多种考虑不好想。
我们从n到0来考虑:
4中操作:
除以2,除以3,除以5,+-1.
前三种操作必须n是2/3/5的倍数,否则必须通过第四种操作加或减到最近的一个倍数然后执行除法操作。//(为什么只考虑最近的倍数呢?显然,你加减到不是最近的倍数,我们完全可以先到最近的倍数然后执行除法,再加减,到想要的位置。比如 (5+1)/3+1 =3 (5+4)/3=3 前者只需要2次+1后者则需要4次,优劣立判)
然后由于是要到0,所以我们尽可能的让数成倍缩小,(或者通过减1达到相同效果),比较两者花费较少的一个。
然后用dp记录到某个数的最小花费,但dp开不下,我们用BFS处理,记忆化一下,即记录在队列里的数,开个map维护到某个数的最小花费。
执行BFS次数等于 2,3,5相乘凑成N的个数。大约是60^3 小于1e6 复杂度完全可以接受。
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
struct node{
ll a,b;
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
ll n,A,B,C,D;
cin>>n>>A>>B>>C>>D;
queueq;
q.push(node{n,0});
ll mi=2e18;
mapmp;
while(q.size())
{
node tp=q.front();q.pop();
tp.b=mp[tp.a];
mp.erase(tp.a);
//cout<=3)
{
z=tp.a/3;
if(tp.a-z<=1e9)e=D*(tp.a-z);else e=1e18;
ll w=tp.b+min(B+D*(tp.a%3),e);
if(mp.find(z)!=mp.end())mp[z]=min(mp[z],w);
else mp[z]=w,q.push(node{z,w});
}
if(tp.a>=5)
{
z=tp.a/5;
if(tp.a-z<=1e9)e=D*(tp.a-z);else e=1e18;
ll w=tp.b+min(C+D*(tp.a%5),e);
if(mp.find(z)!=mp.end())mp[z]=min(mp[z],w);
else mp[z]=w,q.push(node{z,w});
}
}
cout<
B - Joker
开一个数组d记录刚开始时,每个位置最快离开剧场所需要的时间。
每次有一个人离开时,会对一些位置的人造成影响,由于影响只会从上下左右四个位置传播,我们用BFS取更新每次人离开造成的影响(即更新d数组)。加上优化后,每次更新一个位置会让一个位置的d减一。
由于初始所有d的值是n^3级别。
所以复杂度同样是n^3级别。
具体细节看代码
#include
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 500+7;
int x[M*M],y[M*M];
int dx[10]={-1,1,0,0},dy[10]={0,0,-1,1};
int vs[M][M];//i,j位置当前时刻 是否还有人
int d[M][M];//i,j位置的人,最快离开剧场所需要的时间
struct node{
int x,y;
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for(int i=1;i<=n*n;i++){
int z;
cin>>z;
x[i]=(z-1)/n+1;
y[i]=(z-1)%n+1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(min(i-1,n-i),min(j-1,n-j)),vs[i][j]=1;
int ans=0;
for(int i=1;i<=n*n;i++)
{
ans+=d[x[i]][y[i]];
vs[x[i]][y[i]]=0;
queueq;
q.push(node{x[i],y[i]});
while(q.size())
{
node tp=q.front();q.pop();
int tx=tp.x,ty=tp.y;
for(int j=0;j<4;j++)
{
int px=tx+dx[j],py=ty+dy[j];
if(px<1||px>n||py<1||py>n||d[tx][ty]+vs[tx][ty]>=d[px][py]) continue;//px,py 先到 tx,ty 是否更优,如果不优没必要拓展下去
d[px][py]=d[tx][ty]+vs[tx][ty];
q.push(node{px,py});
}
}
}
cout<