哈尔滨水题报告

在网上观战的时候群里算法都说的差不多了,然后杭电把题目挂出来以后和君爷又去做了下,据tracyzhu说知道算法以后再去做要损RP的,希望RP别降太多。基本把水题搞完了,还剩下一个3D凸包,一个DLX和一个O(n)DP,有空再去搞,斜率优化DP基本看完了,过几天估计就能a掉了。

A:

树形DP,treedp(cur,flag)表示访问到cur点,flag为1Alice走取最小的,0表示Bob走取最大的。

做的时候被时限恶心到了,用vectorTLE,改成临接表还是TLE,最后用输入外挂1000msa掉的,不用输入外挂的话把算到根节点距离的那个dfs集成到树形dp里也能1900ms卡过

#include<iostream> #include<vector> using namespace std; #define MAXN 500005 #define INF 2000000000 struct pt { int x,y,next; }; int tr[MAXN]; pt sz[MAXN]; int ts[MAXN]; int dp[MAXN][2]; int dis[MAXN],ans,l,r; void dfs(int cur) { int i; pt cs; if (tr[cur]!=-1) for(cs=sz[tr[cur]];;cs=sz[cs.next]) { dis[cs.x]=dis[cur]+cs.y; dfs(cs.x); if (cs.next==-1) break; } } void treedp(int cur,int flag) { int i,ans; pt cs; if (flag==1) ans=INF; else ans=0; if (tr[cur]!=-1) for(cs=sz[tr[cur]];;cs=sz[cs.next]) { treedp(cs.x,1-flag); if (flag==1) { if ( (dis[cs.x]+dp[cs.x][1-flag]>=l)&&(dis[cs.x]+dp[cs.x][1-flag]<=r)&&(ans>dp[cs.x][1-flag]+cs.y) ) { ans=dp[cs.x][1-flag]+cs.y; } } else if ( (dis[cs.x]+dp[cs.x][1-flag]>=l)&&(dis[cs.x]+dp[cs.x][1-flag]<=r)&&(ans<dp[cs.x][1-flag]+cs.y) ) { ans=dp[cs.x][1-flag]+cs.y; } if (cs.next==-1) break; } if ( (flag==1)&&(tr[cur]==-1) ) ans=0; dp[cur][flag]=ans; } int Input() { int sum=0; char ch; while (ch=getchar()) { if (isdigit(ch)==0) return sum; sum=ch-'0'+sum*10; } return sum; } int main() { int n,i,j,x,y,c,root,k; while(scanf("%d %d %d",&n,&l,&r)!=EOF) { getchar(); memset(tr,-1,sizeof(tr)); k=0; for(i=1;i<=n-1;i++) { // scanf("%d %d %d",&x,&y,&c); x=Input(); y=Input(); c=Input(); pt temp; temp.x=y; temp.y=c; temp.next=tr[x]; tr[x]=k; sz[k++]=temp; ts[x]++; } root=0; // memset(dp,0,sizeof(dp)); // memset(dis,0,sizeof(dis)); dp[0][0]=0; dis[0]=0; dfs(root); treedp(root,0); if ((n==1)&&(l<=0)) {printf("0/n");continue;} if (dp[root][0]==0) printf("Oh,my god!/n"); else printf("%d/n",dp[root][0]); } }

B:

贪心,排序,a从大到小,b从小到大取过来。如果没听群里讨论的话有可能也会跳进匹配这个坑里。

C:

3D凸包不会

D:

DLX不会

E:

推公式,dp[i][k]=dp[i-1][k]*(k+1)+dp[i-1][k-1]*(i-k);

dp[i][k]放完前i个数产生k个e-value的个数,由两部分构成:

首先因为i当前是最大的所以i怎么放e-value都不会减少

1.

   前i-1个数已经有了k个e-value,然后第i个数放到i这个位置上e-value不会增加,放到前面已经产生k个e-value的地方上e-value也不会增加,所以第i个可以放k+1个位置,即dp[i-1][k]*(k+1);

2.

 前i-1个数只有k-1个e-value,所以i这个数放下去必须多出一个e-value,那就只能放到前i-1个位置中没有产生e-value的地方使其多出一个e-value来,可以放i-1-(k-1)个,即dp[i-1][k-1]*(i-k);

F:

10个点的最短路,floyd即可

G:

差分约束

题目要求是否存在2个数组a,b使得L=<a[i]*map[i][j]/b[j]<=U,两遍取对数变成:

log(L)<=log(a[i])+log(map[i][j])-log(b[j])<=U,这样就直接可以套差分约束方程了。

构图:

for(i=1;i<=n+m;i++) map[s].push_back(Node(i,0)); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { map[n+j].push_back(Node(i,u-a[i][j])); map[i].push_back(Node(j+n,a[i][j]-l)); }

H:

 凸费用流,由于流量最多为5,可以将边拆开为(1,1)(1,3)(1,5)(1,7)(1,9)的边,由于是最小费用流,所以每次先流费用小的,要流(1,3)这条边的话(1,1)肯定已经先流过了,这是容量为2,费用为2^2,别的同理。。

#include <iostream> #include <algorithm> #include <cstdio> #include <queue> using namespace std; const int sz = 750000; const int INF = 200000000; int mt[610][610]; struct Edge { int v,w,capacity; int next; }adj[sz * 8]; int head[sz],pre[sz],dist[sz],road[sz],src,dest,k; bool inq[sz]; void init(int s,int t,int n) { src = s; dest = t; k = 0; fill(head,head+n+1,-1); } void add(const int &v1,const int &v2,const int &w,const int &capacity) { adj[k].v = v2; adj[k].w = w; adj[k].capacity = capacity; adj[k].next = head[v1]; head[v1] = k ++; } void addEdge(const int &v1,const int &v2,const int &w,const int &capacity) { add(v1,v2,w,capacity); add(v2,v1,-w,0); } bool SPFA() { fill(dist,dist+dest+1,INF); fill(inq,inq+dest+1,false); inq[src] = true; dist[src] = 0; queue < int > q; q.push(src); while(!q.empty()) { int t = q.front(); q.pop(); inq[t] = false; int index = head[t]; while(index != -1) { if(adj[index].capacity > 0 && dist[t] + adj[index].w < dist[adj[index].v]) { dist[adj[index].v] = dist[t] + adj[index].w; pre[adj[index].v] = t; road[adj[index].v] = index; if(!inq[adj[index].v]) { q.push(adj[index].v); inq[adj[index].v] = true; } } index = adj[index].next; } } return (dist[dest] != INF); } int minCostMaxFlow(int &ans_flow) { int minCost = 0,t; ans_flow=0; while(SPFA()) { int flow = INF; for(t = dest ; t != src ; t = pre[t] ) { if(adj[road[t]].capacity < flow) flow = adj[road[t]].capacity; } ans_flow+=flow; for( t = dest ; t != src ; t = pre[t] ) { adj[road[t]].capacity -= flow; adj[road[t]^1].capacity += flow; minCost += flow * adj[road[t]].w; } } return minCost; } int main() { int n,m,v,ans_v,ans_flow,k; while(~scanf("%d %d %d",&n,&m,&k)) { int s=1,t=n+1,u,v,a,c; init(s,t,t); addEdge(n,n+1,0,k); int i; for(i = 1 ; i <= m ; i ++ ) { scanf("%d %d %d %d",&u,&v,&a,&c); if (c>=1) addEdge(u,v,1*a,1); if (c>=2) addEdge(u,v,3*a,1); if (c>=3) addEdge(u,v,5*a,1); if (c>=4) addEdge(u,v,7*a,1); if (c>=5) addEdge(u,v,9*a,1); } ans_v=minCostMaxFlow(ans_flow); // printf("%d/n",ans_flow); if (ans_flow<k) printf("%d/n",-1); else printf("%d/n",ans_v); } return 0; }

I:

积分,君爷用龙贝格搞的,不解释,据说有O(1)的公式??

J:

几乎就是原题,USACO Monthly,March,2008 Gold,斜率优化DP,还没写过。。

 

你可能感兴趣的:(c,算法,优化,struct,input)