D124 同余最短路 Dijkstra 算法 P8060 [POI 2003] Sums

D124 同余最短路 Dijkstra 算法 P8060 [POI 2003] Sums_哔哩哔哩_bilibili

 

P8060 [POI 2003] Sums - 洛谷

给定 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");
  }
}

 

posted @ 2026-03-30 20:33  董晓  阅读(97)  评论(0)    收藏  举报