D124 同余最短路 Dijkstra 算法 P8060 [POI 2003] Sums
D124 同余最短路 Dijkstra 算法 P8060 [POI 2003] Sums_哔哩哔哩_bilibili
给定 n 个整数,拼凑一个非负整数集合 A,询问 k 次,每次询问一个整数 b,问 b 是否属于集合 A
思路
先找出 $n$ 个整数中最小的整数 $x$
如图为 $4,7,9$ 可拼凑出的整数,模 $4$ 的同余类:$\{4,8,12\},\{9,13,17,21\},\{14,18,22,26\},\{7,11,15,19\}$
同余类节点到 0 点的最短路相同:$d[0]=0,\;d[1]=9,\;d[2]=14,\;d[3]=7$

$d[i]$ 表示第 $i$ 类能拼出来的最小整数,即同余类的第一个数字 $4,9,14,7$
第 $i$ 类能拼出的整数为 $d[i],d[i]+x,d[i]+2x,...$,不能拼出的正整数为 $d[i]-x,d[i]-2x,...$
图中第 $1$ 类不能拼出 $5,1$,第 $2$ 类不能拼出 $10,6,2$,第 $3$ 类不能拼出 $3$
给一个整数 $b$,如果 $d[b\%x]<=b$ 则能拼出,否则不能拼出
注意本题的 $a=5\times 10^4,n=5\times 10^3$,如果直接建图会爆空间,可以在最短路时暴力转移状态
相关板子:
D123【模板】同余最短路 Dijkstra 算法 P2662 [WC2002] 牛场围栏 - 董晓 - 博客园
// 同余最短路 Dijkstra 算法 O(NlogN) #include<bits/stdc++.h> #define int long long #define pii pair<int,int> using namespace std; const int N=5e4+5,inf=1e18; int n,a[N],mi,k,b; int d[N],vis[N]; void dijkstra(){ for(int i=0;i<mi;++i) d[i]=inf; d[0]=0; priority_queue<pii,vector<pii>,greater<pii> > q; q.push({0,0}); while(!q.empty()){ int u=q.top().second; q.pop(); if(vis[u]) continue; vis[u]=1; for(int i=2; i<=n; i++){ //枚举数 int v=(u+a[i])%mi; if(d[v]>d[u]+a[i]){ d[v]=d[u]+a[i]; //最短路 q.push({d[v],v}); } } } } signed main(){ scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+n+1); mi=a[1]; //最小整数 dijkstra(); scanf("%lld",&k); while(k--){ scanf("%lld",&b); printf("%s\n",d[b%mi]<=b?"TAK":"NIE"); } }
浙公网安备 33010602011771号