T1:
f[i]为从i点开始到终点的最大边数期望
考虑不删边时 f[i] = ∑(f[j]+1)/tot j为i点的后继,tot为总边数
令b[j] = f[j]+1 a[j] = 0,1 表示是否选择第j条边
于是f[i] = ∑(b[j]*a[j])/∑a[j] = ans (01分数规划)
二分ans,移项得 ∑a[j]*(b[j]-ans) > 0 也就是说,左式大于零时,ans就还有增大的可能
如果没有限制条件,那么留下所有b[j]-ans>0的边即可
但是题中存在限制条件,即删去y边必须删去x边
将所有边看成点,那么每个点有一个权值(b[j]-ans)
对于每个条件,从x向y连一条边,留着x就必须留下y那么原图变成求出最大权闭合子图
对于所有b[j]-ans>0的点,Add(S,j,b[j]-ans)
对于所有b[j]-ans<0的点,Add(j,T,ans-b[j])
对于每个条件,Add(x,y,INF)
跑一遍最大流,选取s-割中所有点,舍去t-割中所有点,剩下的权值就是左边的式子
(因为x,y的边容量为INF,所以该边一定不存在于最小割,而对于每个(x,y)的条件,因而满足了得到x必得到y,舍去y必舍去x)
。。。总之,左边的式子 = 正权点权值和 - 最小割
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef double DB;
const int maxn = 2E3 + 20;
const int T = 2000;
const int S = 0;
const DB INF = 1234567;
const DB eps = 1E-10;
struct E{
int from,to; DB cap,flow;
E(int _from = 0, int _to = 0, DB _cap = 0, DB _flow = 0){from = _from; to = _to; cap = _cap; flow = _flow;}
}edgs[maxn*20];
int n,m,k,co,cnt,d[60],D[maxn],cur[maxn],vis[maxn];
DB f[60];
vector v[60];
vector num[60];
vector argue[510];
vector p[maxn];
vector v2[60];
queue q;
bool Equal(DB x,DB y)
{
return abs(x - y) <= eps;
}
void Add(int x,int y,DB w)
{
p[x].push_back(co); edgs[co++] = E(x,y,w,0.00);
p[y].push_back(co); edgs[co++] = E(y,x,0.00,0.00);
}
bool BFS()
{
D[S] = 1; ++cnt;
queue Q; Q.push(S); vis[S] = cnt;
while (!Q.empty()) {
int k = Q.front(); Q.pop();
for (int i = 0; i < p[k].size(); i++) {
int Num = p[k][i];
if (Equal(edgs[Num].cap,edgs[Num].flow)) continue;
int to = edgs[Num].to;
if (vis[to] == cnt) continue;
D[to] = D[k] + 1; vis[to] = cnt;
Q.push(to);
}
}
return vis[T] == cnt;
}
DB Dicnic(int x,DB a)
{
if (x == T || Equal(a,0.00)) return a;
DB flow = 0.00;
for (int &i = cur[x]; i < p[x].size(); i++) {
int Num = p[x][i];
if (Equal(edgs[Num].cap,edgs[Num].flow)) continue;
if (D[edgs[Num].to] != D[x] + 1) continue;
DB F = Dicnic(edgs[Num].to,min(a,edgs[Num].cap - edgs[Num].flow));
if (F > 0.00) {
flow += F;
a -= F;
edgs[Num].flow += F;
edgs[Num^1].flow -= F;
if (Equal(a,0.00)) return flow;
}
}
return flow;
}
bool Judge(int x,DB now)
{
DB tot = 0; co = 0;
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i],Num = num[x][i];
DB t = f[to] + 1.00 - now;
if (t > 0) Add(S,Num,t),tot += t;
else Add(Num,T,-t);
for (int j = 0; j < argue[Num].size(); j++)
Add(Num,argue[Num][j],INF);
}
while (BFS()) {
for (int i = 0; i < num[x].size(); i++) cur[num[x][i]] = 0; cur[S] = cur[T] = 0;
tot -= Dicnic(S,INF);
}
p[S].clear(); p[T].clear();
for (int i = 0; i < v[x].size(); i++) p[num[x][i]].clear();
return tot > 0;
}
void Work(int k)
{
DB L = 0,R = 500.00;
for (int i = 0; i < 20; i++) {
DB mid = (L+R) / 2.00;
if (Judge(k,mid)) L = mid;
else R = mid;
}
f[k] = L;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("trip.in","r",stdin);
freopen("trip.out","w",stdout);
#endif
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
int x,y; scanf("%d%d",&x,&y);
v[x].push_back(y); ++d[x];
num[x].push_back(i); v2[y].push_back(x);
}
for (int i = 1; i <= k; i++) {
int x,y; scanf("%d%d",&x,&y);
argue[x].push_back(y);
//argue[y].push_back(x);
}
for (int i = 1; i <= n; i++)
if (!d[i]) q.push(i);
while (!q.empty()) {
int k = q.front(); q.pop();
Work(k);
for (int i = 0; i < v2[k].size(); i++) {
int F = v2[k][i];
--d[F];
if (!d[F]) q.push(F);
}
}
printf("%.5f",f[1]);
return 0;
}
一次函数满足结合律不满足交换律,线段树维护一下即可
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn = 2E5 + 20;
const LL mo = 1000000007LL;
LL k[maxn*20],b[maxn*20];
int n,m;
void Insert(int o,int l,int r,int pos,LL K,LL B)
{
if (l == r) {k[o] = K; b[o] = B; return;}
int mid = (l+r) >> 1;
if (pos <= mid) Insert(2*o,l,mid,pos,K,B);
else Insert(2*o+1,mid+1,r,pos,K,B);
k[o] = k[2*o]*k[2*o+1]%mo;
b[o] = (k[2*o+1]*b[2*o]%mo + b[2*o+1])%mo;
}
int query(int o,int l,int r,int ql,int qr,LL x)
{
if (ql <= l && r <= qr) return (k[o]*x%mo + b[o])%mo;
int mid = (l+r) >> 1;
int ret = x;
if (ql <= mid) ret = query(2*o,l,mid,ql,qr,x);
if (qr > mid) ret = query(2*o+1,mid+1,r,ql,qr,ret);
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("func.in","r",stdin);
freopen("func.out","w",stdout);
#endif
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int x,y; scanf("%d%d",&x,&y);
Insert(1,1,n,i,x,y);
}
while (m--) {
char ch = getchar();
while (ch != 'Q' && ch != 'M') ch = getchar();
if (ch == 'Q') {
int l,r,x; scanf("%d%d%d",&l,&r,&x);
printf("%d\n",query(1,1,n,l,r,x));
}
else {
int po,x,y; scanf("%d%d%d",&po,&x,&y);
Insert(1,1,n,po,x,y);
}
}
return 0;
}
求五维偏序
对于每科成绩的每个点维护一个bitset(比他低的标1比他高的标0),对于金将军的每次成绩,二分各科所在的bitset的位置,将五个bitset &,统计1的个数就是答案
但是,开不下n^2个bitset,于是每科开sqrt(n)个bitsest,二分所在后剩下一点位置暴力一下,(细节见代码),复杂度挺棒的
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 5E4 + 50;
const int maxm = 300;
struct S{
int score,rank;
bool operator < (const S &b) const {
return score < b.score;
}
}s[5][maxn];
int n,m,T,B,tot,bl[maxn],br[maxn],King[5];
bitset bi[5][maxm];
bitset Ans,ans[5];
int Read()
{
int ret = 0;
char ch = getchar();
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9') ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
freopen("test.txt","w",stdout);
#else
freopen("score.in","r",stdin);
freopen("score.out","w",stdout);
#endif
T = Read();
while (T--) {
n = Read(); m = Read(); B = sqrt(n);
for (int i = 1; i <= n; i++)
for (int j = 0; j < 5; j++)
s[j][i].score = Read(),s[j][i].rank = i;
tot = n/B; if (n%B != 0) ++tot;
bl[1] = 1; br[tot] = n; br[1] = B;
for (int i = 2; i <= tot; i++) bl[i] = bl[i-1] + B;
for (int i = 2; i < tot; i++) br[i] = br[i-1] + B;
for (int i = 0; i < 5; i++) {
sort(s[i] + 1,s[i] + n + 1);
int po = 1; bi[i][1].reset();
for (int j = 1; j <= n; j++) {
if (j > br[po]) bi[i][po+1] = bi[i][po],++po;
bi[i][po][s[i][j].rank] = 1;
}
}
int Q,Lastans = 0; Q = Read();
while (Q--) {
for (int i = 0; i < 5; i++) King[i] = Read() ^ Lastans;
Ans.set();
for (int k = 0; k < 5; k++) {
int L = 1,R = n;
while (R - L > 1) {
int mid = (L+R) >> 1;
if (s[k][mid].score <= King[k]) L = mid;
else R = mid;
}
int pos = s[k][R].score <= King[k]?R:L;
if (s[k][L].score > King[k]) pos = 0;
ans[k] = bi[k][pos/B];
if (pos%B != 0) {
int P = pos/B + 1;
for (int i = bl[P]; i <= pos; i++)
ans[k][s[k][i].rank] = 1;
}
Ans &= ans[k];
}
printf("%d\n",Lastans = Ans.count());
}
}
return 0;
}