题意:
log(a[i]) - log(b[j]) >= L'
log(a[i]) - log(b[j]) <= R'
在网上看到两种优化,
(1)不必判断某一个点入队次数大于N,只要判断是否大于sqrt(1.0*N)。
(2)或者所有点的入队次数大于T*N,即存在负环,一般T取2。
其中,N为所有点的个数。
给一个N*M的矩阵,是否存在两列数a1,a2,a3...an 和 b1,b2.....bm使得对矩阵中的每个数进行下面的操作之后的值在[L,U]之间,操作为:a[i] * m[i][j] / b[j]。 N,M<=400
思路:
首先能得到式子 L <= c[ij]*a[i]/b[j] <= R,然后同时除以c[ij]得 L' <= a[i]/b[j] <= R',再取log我们就得到了两个不等式:log(a[i]) - log(b[j]) >= L'
log(a[i]) - log(b[j]) <= R'
由于a(i),b(j)都可取任何值,所以不必进行约束条件,至此所有约束条件用完了,于是建图差分约束即可。
在网上看到两种优化,
(1)不必判断某一个点入队次数大于N,只要判断是否大于sqrt(1.0*N)。
(2)或者所有点的入队次数大于T*N,即存在负环,一般T取2。
其中,N为所有点的个数。
但是,第二个优化在本题就用不了,第一个的正确性也不得而知,所以做题时先正常地>N,没办法再尝试这个优化。
代码:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 805;
const int maxm = 160005*2;
struct node
{
int v, next;
double w;
}edge[maxm];
int no, head[maxn];
int vis[maxn], cnt[maxn];
double dis[maxn];
queue<int> q;
int N, M, L, R;
inline void init()
{
no = 0;
memset(head, -1, sizeof head);
}
inline void add(int u, int v, double w)
{
edge[no].v = v; edge[no].w = w;
edge[no].next = head[u]; head[u] = no++;
}
int SPFA()
{
memset(vis, 0, sizeof vis);
fill(dis+1, dis+N+M+1, inf);
memset(cnt, 0, sizeof cnt);
while(!q.empty()) q.pop();
dis[1] = 0;
q.push(1); vis[1] = 1;
while(!q.empty())
{
int u = q.front(); q.pop();
vis[u] = 0; ++cnt[u];
if(cnt[u] > sqrt(N+M)) return -1;
for(int k = head[u]; k != -1; k = edge[k].next)
{
int v = edge[k].v;
if(dis[v] > dis[u]+edge[k].w)
{
dis[v] = dis[u]+edge[k].w;
if(!vis[v]) vis[v] = 1, q.push(v);
}
}
}
return 1;
}
int main()
{
//freopen("in.txt", "r", stdin);
int x;
while(~scanf("%d %d %d %d", &N, &M, &L, &R))
{
init();
for(int i = 1; i <= N; ++i)
for(int j = 1; j <= M; ++j)
{
scanf("%d", &x);
double _L = log(1.0*L/x);
double _R = log(1.0*R/x);
add(i, N+j, -_L);
add(N+j, i, _R);
}
if(SPFA() != -1) puts("YES");
else puts("NO");
}
return 0;
}
差分约束:当题目中存在大于某数小于某数,求两个变量之间的至少值最多值,在大于小于约束条件下的成不成功存不存在,都要尝试考虑考虑差分约束!然后再尝试构建减法,除法通过取log构建减法,但加法和乘法貌似不可行,因为对第二个数取负会是什么意义?第二个数是为了代表一个点啊!不过某些题估计也可行,遇到题目再分析吧。
继续加油~