原题链接:D-Tokitsukaze and Slash Draw
题目大意:从下到上有n个牌,居合卡是从下往上第k个牌,有m种操作,可以从最上面依次拿a个牌放到最下面,操作一次有b的代价,可以操作无数次。要求求出让居合卡到最上面的最小代价。
思路:如果一共有4张牌,一个操作可以让最上面的2张牌到最下面,那么对于所有牌的影响是1->3,2->4,3->1,4->2。观察可以知道,每一次操作会对全部的牌都有影响,所以可以根据操作来建图,对于上面举的例子就是从1到3,从2到4,从3到1,从4到2,连上一条边。然后跑从k到n的最短路。观察题目数据可以知道,极端情况下n==5000,m==1000,因为不管操作是对上面的多少张牌进行,都会让在图中连上n条边,所以一共会有n*m条边。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=5e6+10;//5000*1000
ll h[5010],e[N],ne[N],idx,w[N];
ll n,m,k,d[N];
bool st[N];
void add(ll a,ll b,ll c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void dij()
{
priority_queue<pii,vector<pii>,greater<pii>> op;
op.push({0,k-1});
while(op.size())
{
auto v=op.top();op.pop();
ll x=v.first,y=v.second;
if(st[y])continue;
st[y]=1;
for(int i=h[y];~i;i=ne[i])
{
ll j=e[i];
if(d[j]>w[i]+d[y])
{
d[j]=w[i]+d[y];
op.push({d[j],j});
}
}
}
}
int main()
{
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
ll t;cin>>t;
while(t--)
{
cin>>n>>m>>k;
bool l=0;
idx=0;
for(int i=0;i<=n;i++)st[i]=0,d[i]=1e18,h[i]=-1;//不建议使用memset,有些题目会T
ll a,b;
for(int i=0;i<m;i++)
{
cin>>a>>b;
for(int i=0;i<n;i++)//把1到n,映射到0到n-1
{
add(i,(i+a)%n,b);
}
}
d[k-1]=0;
dij();
if(d[n-1]==1e18)cout<<-1<<endl;
else cout<<d[n-1]<<endl;
}
return 0;
}