P2371 [国家集训队] 墨墨的等式
P2371 [国家集训队] 墨墨的等式
题目描述
墨墨突然对等式很感兴趣,他正在研究 \(\sum_{i=1}^n a_ix_i=b\) 存在非负整数解的条件,他要求你编写一个程序,给定 \(n, a_{1\dots n}, l, r\),求出有多少 \(b\in[l,r]\) 可以使等式存在非负整数解。
输入格式
第一行三个整数 \(n,l,r\)。
第二行 \(n\) 个整数 \(a_{1\dots n}\)。
输出格式
一行一个整数,表示有多少 \(b\in[l,r]\) 可以使等式存在非负整数解。
输入输出样例 #1
输入 #1
2 5 10
3 5
输出 #1
5
说明/提示
对于 \(20\%\) 的数据,\(n \le 5\),\(r \le 10\)。
对于 \(40\%\) 的数据,\(n \le 10\),\(r \le 10^6\)。
对于 \(100\%\) 的数据,\(n \le 12\),\(0 \le a_i \le 5\times 10^5\),\(1 \le l \le r \le 10^{12}\)。
结题报告
首先考虑暴力的做法
设 \(dp[i]\) 表示 $ \sum_{j=1}^n a_j \times x_j=i $ 是否可以表示
这是一个完全背包问题,转移方程为 \(dp[i]|=dp[i-a_j] ( 1<=j<=n )\)
对于 1E+18 量级 的 \(L\)和\(R\) ,这样做显然不行
考虑 差分,$ ans[l,r]=ans[0,r]-ans[0,l-1] $
问题变为 求给定区间 $ [0,x] $ 中的方案数
设 \(mod\) 为 任意的 \(a_i\)
当 $ \sum_{j=1}^n a_j \times x_j=i $时
则有 $ \sum_{j=1}^n a_j \times x_j=i + k*mod $, \(k\)为任意自然数
这说明 当 \(i\) 合法时,与 \(i\) 同余的数 同样合法
同时,当 \(i\) 最小时,合法方案 最多
那么,只需要找到 每个余数\([0,mod-1]\) 最小的合法的 \(i\)
我们就可以计算 任意一个余数的合法方案数
设 \(dis[r]\) 表示 余数为\(r\) 时最小的 \(i\)
那么在 \([0,x]\) 内就有 \(( x-dis[r] )/mod+1\) 个合法方案
那么现在的问题是,如何求解 \(dis[r] (0<=r<mod)\)
显然 自然数\(0\) 总可以被表示,它的同余类总是有合法方案
考虑与 \(dp\) 类似的想法,我们考虑 各个同余类 之间的转移
显然 ,可以 从 余数\(r\) 通过加上任意一个\(a_j\) 转移到$ (r+a_j)%mod$
结合 \(0\)所属的同余类 总是合法
当我们从 \(0\) 开始转移时,就可以得出各个余数的合法的i
但是,经过上面分析,我们要求的实际是最小的 \(i\) ,即\(dis[r]\)
一个很好的表示转移的方法 是 用单向边表示
对于 余数\(r\) 加上任意一个\(a_j\) 转移到 \((r+a_j) \bmod mod\)
可以 建一条 \(r\) 到 \((r+a_j) \bmod mod\) 权值 为 \(a_j\) 的单向边 , 表示 一次转移
这样就可以通过最短路算法,计算 每个同余类\(r\) 的 \(dis[r]\)
就可以快速计算结果了
一般为了 减少边数以加快速度,\(mod\)取最小的 \(a_i\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF=(1E+12)+10;
const int N=5001100;
inline int read()
{
int f=1,x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
return f*x;
}
int n,m,L,R;
int a[N],g;
struct edge
{
int next,to;
int dis;
}e[N<<1];
int head[N],tot;
int mod=INF;
inline void add_edge(int u,int v,int w)
{
e[tot]=(edge){ head[u],v,w };
head[u]=tot++;
}
struct node
{
int pos,dis;
bool operator < (const node &x)const
{ return x.dis<dis; }
};
int dis[N];
bool vis[N];
void dijkstra(int s)
{
priority_queue<node> q;
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
q.push( (node){ s,dis[s]=0 } );
vis[s]=true;
while(!q.empty())
{
int u=q.top().pos; q.pop();
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].dis)
{
dis[v]=dis[u]+e[i].dis;
if(!vis[v])
{
vis[v]=true;
q.push( (node){ v,dis[v] } );
}
}
}
}
}
inline int calc(int x)
{
int ans=0;
for(int i=0;i<mod;i++)
if(dis[i]<=x)
ans+=(x-dis[i])/mod+1;
return ans;
}
signed main()
{
// 洛谷P2371 [国家集训队] 墨墨的等式
freopen("equation.in","r",stdin);
freopen("equation.out","w",stdout);
memset(head,-1,sizeof(head));
n=read(),L=read(),R=read();
for(int i=1;i<=n;i++)
{
int x=read();
if(x) mod=min(mod,a[++m]=x);
}
n=m;
for(int i=0;i<mod;i++)
for(int j=1;j<=n;j++)
if(a[j]!=mod)
add_edge(i,(i+a[j])%mod,a[j]);
dijkstra(0);
printf("%lld",calc(R)-calc(L-1));
return 0;
}

浙公网安备 33010602011771号