2016长乐夏令营 Day5

来源:互联网 发布:java 文件编码 编辑:程序博客网 时间:2024/04/29 17:03

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<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<stack>#include<cstdlib>#include<cmath>#include<algorithm>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 <int> v[60];vector <int> num[60];vector <int> argue[510];vector <int> p[maxn]; vector <int> v2[60];queue <int> 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 <int> 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 DMCfreopen("DMC.txt","r",stdin);    #elsefreopen("trip.in","r",stdin);freopen("trip.out","w",stdout);#endifcin >> 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;}



T2:

一次函数满足结合律不满足交换律,线段树维护一下即可

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<stack>#include<cstdlib>#include<cmath>#include<algorithm>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 DMCfreopen("DMC.txt","r",stdin);    #elsefreopen("func.in","r",stdin);freopen("func.out","w",stdout);#endifcin >> 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;}


T3:

求五维偏序

对于每科成绩的每个点维护一个bitset(比他低的标1比他高的标0),对于金将军的每次成绩,二分各科所在的bitset的位置,将五个bitset &,统计1的个数就是答案

但是,开不下n^2个bitset,于是每科开sqrt(n)个bitsest,二分所在后剩下一点位置暴力一下,(细节见代码),复杂度挺棒的

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<stack>#include<cstdlib>#include<cmath>#include<algorithm>#include<bitset>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 <maxn> bi[5][maxm];bitset <maxn> 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 DMCfreopen("DMC.txt","r",stdin);freopen("test.txt","w",stdout);     #elsefreopen("score.in","r",stdin);freopen("score.out","w",stdout);#endifT = 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;}


0 0