南阳CCPC补题:UESTC 1225(dp……另附对拍器)+UESTC 1220(最短路,费用流)+UESTC 1219(高斯消元)
1225
题目:有一栋楼,每层楼上有t个人打网球,有p个人游泳,但是每层只能建一种健身设施。每个人的花费是他到最近的对应设施的楼层距离。问最小总花费。
思路:dp[i][j][k]表示做到第i层的时候选j,和j不同的设施最近在第k层的最小花费,那么如果该层选得和上面一样那么k不变,这个好转移。如果和上一层不一样,那么k层到当前层i的玩家会有一部分重新分布(他们的选择显然以中点为准),这个需要预处理一下(我写得很恶心。。。)。然后wa了整整一天,最后找了个代码对拍了一下才过(基本上完全是对的,,有个初始化没做。。。真是哔了狗。。)。这个对拍器真是好使啊。。。。
丑陋的代码。。
/* * @author: Cwind */ #include <bits/stdc++.h> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define IINF (1<<29) #define LINF (1ll<<49) #define INF (1000000300) #define FINF (1e9) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const int maxn=5000; int T; int n; ll t[maxn],p[maxn]; ll ts[2][maxn],ps[2][maxn]; ll tmm[2][maxn],pm[2][maxn]; ll dp[2][2][maxn]; void cal(){ for(int i=1;i<=n;i++){ ts[0][i]=ts[0][i-1]+t[i]; ps[0][i]=ps[0][i-1]+p[i]; tmm[0][i]=tmm[0][i-1]+t[i]*i; pm[0][i]=pm[0][i-1]+p[i]*i; } ts[1][n+1]=ps[1][n+1]=0; tmm[1][n+1]=pm[1][n+1]=0; for(int i=n;i>=1;i--){ ts[1][i]=ts[1][i+1]+t[i]; ps[1][i]=ps[1][i+1]+p[i]; tmm[1][i]=tmm[1][i+1]+t[i]*(n-i+1); pm[1][i]=pm[1][i+1]+p[i]*(n-i+1); } } ll get(bool o,int l,int r){ int m=(r+l)/2; if(o){ if(l==0) return tmm[1][1]-tmm[1][r+1]-(ts[1][1]-ts[1][r+1])*(n-r+1); ll oc=tmm[0][r]-tmm[0][l-1]-(ts[0][r]-ts[0][l-1])*l; ll nc=tmm[0][m]-tmm[0][l-1]-(ts[0][m]-ts[0][l-1])*l+tmm[1][m+1]-tmm[1][r+1] -(ts[1][m+1]-ts[1][r+1])*(n-r+1)+t[r]*(r-l); return nc-oc; }else{ if(l==0) return pm[1][1]-pm[1][r+1]-(ps[1][1]-ps[1][r+1])*(n-r+1); ll oc=pm[0][r]-pm[0][l-1]-(ps[0][r]-ps[0][l-1])*l; ll nc=pm[0][m]-pm[0][l-1]-(ps[0][m]-ps[0][l-1])*l+pm[1][m+1]-pm[1][r+1] -(ps[1][m+1]-ps[1][r+1])*(n-r+1)+p[r]*(r-l); return nc-oc; } } int cas; int main(){ //freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("/home/slyfc/CppFiles/out","w",stdout); cin>>T; while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld%lld",&t[i],&p[i]); cal(); for(int i=0;i<2;i++) for(int k=0;k<2;k++) for(int j=0;j<maxn;j++) dp[i][k][j]=LINF; dp[0][0][0]=dp[0][1][0]=0; dp[1][0][0]=dp[1][1][0]=0; bool f=0; for(int i=2;i<=n;i++){ f^=1; for(int j=1;j<i-1;j++){ dp[f][0][j]=dp[f^1][0][j]+p[i]*(i-j); dp[f][1][j]=dp[f^1][1][j]+t[i]*(i-j); } for(int j=0;j<i-1;j++){ dp[f][0][i-1]=min(dp[f][0][i-1],dp[f^1][1][j]+p[i]+get(1,j,i)); dp[f][1][i-1]=min(dp[f][1][i-1],dp[f^1][0][j]+t[i]+get(0,j,i)); } } ll ans=LINF; for(int i=1;i<n;i++){ ans=min(ans,dp[f][1][i]); ans=min(ans,dp[f][0][i]); } printf("Case #%d: %lld\n",++cas,ans); } return 0; }
对拍器
while true; do ./make>inData #出数据 ./myCpp<inData>myOut #被测程序 ./stdCpp<inData>stdOut #正确(暴力)程序 if diff myOut stdOut; then #比较两个输出文件 printf AC #结果相同显示AC else echo WA #结果不同显示WA,并退出 #cat tmp.out tmp2.out exit 0 fi #if的结束标志,与C语言相反,0为真 done # while的结束标志 #BY NICK WONG 2014-08-29 #在终端下,进入当前目录,输入"sh ./nick.sh",(其中nick.sh为当前shell脚本名) '#'表示单行注释 #diff在两文件相同时返回空串
对拍器转自:http://blog.csdn.net/nickwong_/article/details/38931579
1220
题目:曹操和袁绍决战,曹操当然想赢啦。但是袁绍势力太大,曹操征兵也会有同样多的人跑去袁绍那边= =。有M个战场,N个村庄。曹操在村庄i征一个兵花费w,可以送到x战场去,同时有同样数量的兵会跑去y战场的袁绍阵营。每个战场有个重要度,重要度为0表示无所谓输赢,为1表示不能输(己方人数不少于敌方),为2表示己方人数必须大于敌方。问能否赢和最小花费。
思路:考虑每个战场己方的净人数,那么实际上征兵对应于x战场增加1,y战场减少1,最后重要战场的净人数大于1(实际上肯定是正好为1)。那么可以建图跑费用流,每个y向x连边,s向重要度0的连边,重要度为2的向t连边。这样每个重要度1的点由于不会与s和t连边,净流为0(人数为0)。重要度为2的点满流(流量1)可以胜利。对应的由于连出s的边净流量不为0,正好对应着重要度为0的点(流量任意)。然后这样会t。实际上费用流是每次沿最短路增广的做法,这个题实际上也是最短路。因为实际上本题不会出现已经分配的流量再退回去的情况。对于任何一条从s到重要度2的点的最短路,必然从重要度为0的点出发,途径若干重要度1的点最后到达重要读2的点。这个过程中总流量没有限制,增加的费用其实是最短路的长度。对应从起点转移1个人到终点,中间点的人数并没有变化(净人数的想法很关键!!)
/* * @author: Cwind */ #include <bits/stdc++.h> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define IINF (1<<29) #define LINF (1ll<<49) #define INF (1000000300) #define FINF (1e9) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) typedef long long ll; typedef unsigned long long ull; typedef pair<ll,int> P; typedef pair<int,int> pp; const int maxn=1e5+300; const ll inf=1e18; int T; int N,M; int x[maxn],y[maxn],c[maxn],w[maxn]; int cas; const int s=maxn-1; ll dis[maxn]; vector<pp> G[maxn]; void dij(){ fill(dis,dis+maxn,inf); priority_queue<P,vector<P>,greater<P> > Q; dis[s]=0; Q.push(P(0,s)); while(!Q.empty()){ int u=Q.top().se; ll d=Q.top().fs;Q.pop(); if(d>dis[u]) continue; for(int i=0;i<G[u].size();i++){ int v=G[u][i].fs,d=G[u][i].se; if(dis[v]>dis[u]+d){ dis[v]=dis[u]+d; Q.push(P(dis[v],v)); } } } } void init(){ for(int i=0;i<=M;i++){ G[i].clear(); } G[s].clear(); } void addedge(int from,int to,int d){G[from].pb(pp(to,d));} int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("/home/slyfc/CppFiles/out","w",stdout); cin>>T; while(T--){ scanf("%d%d",&N,&M); init(); int f=0; for(int i=1;i<=N;i++) scanf("%d",&x[i]); for(int i=1;i<=N;i++) scanf("%d",&y[i]); for(int i=1;i<=N;i++) scanf("%d",&c[i]); for(int i=1;i<=M;i++) scanf("%d",&w[i]); for(int i=1;i<=M;i++) if(w[i]==0){ addedge(s,i,0); } for(int i=1;i<=N;i++){ addedge(y[i],x[i],c[i]); } dij(); ll cost=0; for(int i=1;i<=M;i++){ if(w[i]<2) continue; if(dis[i]==inf){ cost=-1; break; } cost+=dis[i]; } printf("Case #%d: %lld\n",++cas,cost); } return 0; }
1219
题目:求一个无向图中的一个环路使得路径上的权值异或和最大。
思路:“任意一个环路都是由某些环路线性组合而成",那么我们从任意点出发求出部分环路的异或和,然后高斯消元,最后再求最大值即可。
/* * @author: Cwind */ #include <bits/stdc++.h> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define IINF (1<<29) #define LINF (1ll<<49) #define INF (1000000300) #define FINF (1e9) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) typedef long long ll; typedef unsigned long long ull; typedef pair<ll,int> P; typedef pair<int,int> pp; const int maxn=5e4+300; int T; struct EDGE{ int to; ll w; EDGE(int to,ull w):to(to),w(w){} }; vector<EDGE> G[maxn]; int n,m; bool vis[maxn]; ll val[600]; ll up[500]; ll xx[maxn]; void init(){ for(int i=0;i<=n;i++){ G[i].clear(); } memset(vis,0,sizeof vis); memset(val,0,sizeof val); ll x=1; up[0]=x; for(int i=1;i<63;i++){ x<<=1; up[i]=x; } } void add(ll v){ if(v==0) return; int bit=0; for(int i=0;i<63;i++){ if(v>=up[i]) bit=i; } for(int i=bit;i>=0;i--){ if(v==0) break; if(v<up[i]) continue; if(val[i]==0){ val[i]=v; break; }else{ v=val[i]^v; } } } void dfs(int v,ll num){ vis[v]=1; xx[v]=num; for(int i=0;i<G[v].size();i++){ EDGE &e=G[v][i]; if(!vis[e.to]) dfs(e.to,num^e.w); else add(num^e.w^xx[e.to]); } } int cas; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("/home/slyfc/CppFiles/out","w",stdout); cin>>T; while(T--){ scanf("%d%d",&n,&m); init(); int s; for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); ull c; cin>>c; G[a].pb(EDGE(b,c)); G[b].pb(EDGE(a,c)); s=a; } dfs(s,0); ll ans=0; for(int i=63;i>=0;i--) ans=max(ans,ans^val[i]); printf("Case #%d: %lld\n",++cas,ans); } return 0; }