【UOJ】UOJ Easy Round #8
记错时间了,,,开始了一个小时才进来orz,然后第一题第一次做这种通信题,发现挺有趣的,和平时做的题思维都不太一样,考后发现自己算法是假的,只有50,然后B题只会暴力网络流(实施证明暴力网络流只给了5分orz,以为网络流很好可以过20的,就没有写DP),特判分又写挂。然后第三题感觉似乎可做,问先序遍历哪个其实就是序列的删除和插入嘛,然后,,十分自闭地想了50多分钟怎么处理k级祖先。按照常理,维护好了先序遍历和已知中序遍历应该处理出k级祖先应该不难的啊,然而orz,也没来得及写暴力了.最后菜鸡55分,rank50+收场,果然还是太菜了orz.
UER #8 题解
A题 打雪仗
题意:两个人在通信(就是这边的输入等于那边的输出,那边的输出等于这边的输入,提交两个程序),A有一个长度2000的01字符串,B有1000个下标,B顺序输出下标对应的所有字符串,通信两边都不能超过1350,只能输出0或1. 想法十分有趣,我们把2000长度分成三块,那么对于B一定知道哪块里面有超过块长一半的答案(即>334),这样的话,他只要传达消息给A让他把这一块全部发过来,然后B就一一把剩下块的每个字符是不是答案发给A,对于A,还需要发的一定不到2n/3,总共发送4/3n,对于B,要完全发送剩下两块,也恰好是4/3n,这样,我们就卡着死亡边缘通过了此题。 alice :#include <iostream> #include <fstream> #include <string> using namespace std; ifstream fin; char get_bit() { return getchar(); } void send_bit(char ch) { putchar(ch); fflush(stdout); } int n, m; string s; struct init_t { init_t() { fin.open("alice.in"); fin >> n >> m >> s; } } init_t; int main() { string s1,s2,s3; s1 = s.substr(0,668); s2 = s.substr(668,668); s3 = s.substr(1336,664); char t1 = get_bit(); char t2 = get_bit(); int t = 1; if(t1=='0'&&t2=='1') { t = 1; } else if(t1=='1'&&t2=='0') { t = 2; swap(s1,s2); } else { t = 3; swap(s1,s3); } for(int i=0;i<s1.size();i++) { send_bit(s1[i]); } for(int i=0;i<s2.size();i++) { char o = get_bit(); if(o=='1') send_bit(s2[i]); } for(int i=0;i<s3.size();i++) { char o = get_bit(); if(o=='1') send_bit(s3[i]); } }Bob:
#include <iostream> #include <fstream> #include <string> #include<cstring> using namespace std; ifstream fin; char get_bit() { return getchar(); } void send_bit(char ch) { putchar(ch); fflush(stdout); } ofstream fout; void answer(string s) { fout << s << endl, exit(0); } const int N = 1000; int n, m, pos[N + 1]; struct init_t { init_t() { int x; fin.open("bob.in"); fout.open("bob.out"); fin >> n >> m; for (x = 1; x <= n; ++x) fin >> pos[x]; } } init_t; int getcnt(string s) { int ans = 0; int le = s.size(); for(int i=0;i<le;i++) if(s[i]=='1') ans++; return ans; } int main() { string s; string s1,s2,s3; for(int i=1;i<=2*n;i++) s+='0'; for(int i=1;i<=n;i++) { s[pos[i]-1]='1'; } s1 = s.substr(0,668); s2 = s.substr(668,668); s3 = s.substr(1336,664); int t; if(getcnt(s1)>334) { t = 1; send_bit('0'); send_bit('1'); } else if(getcnt(s2)>334) { t = 2; swap(s1,s2); send_bit('1'); send_bit('0'); } else { swap(s1,s3); t = 3; send_bit('1'); send_bit('1'); } string ans1,ans2,ans3; for(int i=0;i<s1.size();i++) { char t = get_bit(); if(s1[i]=='1') ans1+=t; } for(int i=0;i<s2.size();i++) { send_bit(s2[i]); if(s2[i]=='1') ans2+=get_bit(); } for(int i=0;i<s3.size();i++) { send_bit(s3[i]); if(s3[i]=='1') ans3+=get_bit(); } if(t==2) swap(ans1,ans2); if(t==3) swap(ans1,ans3); string ans = ans1 + ans2 + ans3; answer(ans); }
B题 雪灾与外卖
题意:n个人m个商店 n m 1e5 , 每个人和每个商店都有坐标,每一个人都要走到一个商店里去,商店可以进的人有个数限制,且不同商店进一个人花的代价不同。总代价为n个人移动的总距离+总进入商店花的代价(题目可以看成一个费用流) 一个很神的后悔堆orz考场网络流瞬间爆炸。考虑将餐厅和送餐员一起放在坐标轴上排序之后,每次送餐员都考虑一个向左边的一个食品店进行匹配,从食品堆提出w-yi最小的(因为从左向右考虑就不需要绝对值)然后把反悔放进送餐员堆里,然后扫到餐厅的时候,看会不会比当前的以匹配的食品店堆顶好,如果好就再考虑替换掉前面的送餐员,然后放进食品店堆里。这时候,我们如果再将送餐员再次反悔,发现时间复杂度就不对了,因为一个送餐员被反悔替换之后又可能被反悔替换了多次。 事实上,我们的送餐员不需要再次反悔。感性理解就是我们选择两个餐厅的时候,反悔进入堆的东西是等权的(因为送餐员是不用权的,距离是同等生效的)#include<stdio.h> #include<cstdio> #include<queue> #include<algorithm> #include<iostream> #include<vector> #define fi first #define se second using namespace std; typedef long long ll; typedef pair<ll,ll> pr; priority_queue<pr,vector<pr>,greater<pr> >man,food; const int maxn = 2e5+5; int n,m; ll ans = 0; int x[maxn],y[maxn],w[maxn],c[maxn]; pr ve[maxn]; int tp; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&x[i]); ve[++tp] = pr(x[i],0); } ll sm = 0; for(int i=1;i<=m;i++) { scanf("%d%d%d",&y[i],&w[i],&c[i]); if(c[i]>0) ve[++tp] = pr(y[i],i); sm += c[i]; } if(sm<n) { puts("-1"); return 0; } food.push(pr(1e18,n)); sort(ve+1,ve+1+tp); for(int i=1;i<=tp;i++) { pr now = ve[i]; if(now.se == 0 ) { pr tt = food.top(); food.pop(); ans += now.fi + tt.fi; if(--tt.se>0) food.push(tt); man.push( pr(-now.fi*2-tt.fi, 1 ) ); } else { ll cc = c[now.se]; ll ww = w[now.se]; if(food.top().fi+now.fi>ww) { ans += ww*cc; man.push(pr(-ww-now.fi,cc)); while(cc) { pr orz = man.top(); man.pop(); ll oo = min(cc,orz.se); cc-=oo; orz.se-=oo; ans += oo*(now.fi+orz.fi); if(orz.se) man.push(orz); food.push(pr(-now.fi*2-orz.fi,oo)); } } else food.push(pr(ww-now.fi,cc)); } } printf("%lld",ans); }