2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror) in codeforces(codeforces730)
A.Toda 2
思路:可以有二分来得到最后的数值,然后每次排序去掉最大的两个,或者3个(奇数时)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016��10��24�� ����һ 15ʱ00��28�� 4 **Problem** : /media/ray/708898B888987E72/Users/Administrator/Desktop/2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)/erfen_a.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef long long ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 110; 32 33 int a[maxn],n; 34 35 struct node{ 36 int i,v; 37 }b[maxn]; 38 vector<string> outp; 39 bool cmp(const node &a,const node &b){ 40 return a.v>b.v; 41 } 42 bool check(int tar){ 43 if(tar==0)return true; 44 for(int i=1;i<=n;i++)b[i]=(node){i,a[i]-tar}; 45 sort(b+1,b+1+n,cmp); 46 47 int leftsu=0; 48 for(int i=2;i<=n;i++)leftsu+=b[i].v; 49 if(leftsu<b[1].v)return false; 50 if(n==2&&(b[1].v+leftsu)%2!=0)return false; 51 return true; 52 } 53 void add(int i,int j){ 54 string t; 55 for(int i=0;i<n;i++)t+='0'; 56 t[i-1]=t[j-1]='1'; 57 outp.push_back(t); 58 } 59 void add(int i,int j,int k){ 60 string t; 61 for(int i=0;i<n;i++)t+='0'; 62 t[i-1]=t[j-1]=t[k-1]='1'; 63 outp.push_back(t); 64 } 65 void out(int tar){ 66 printf("%d\n",tar); 67 if(tar==0){ 68 for(int i=1;i<n;i++)for(int j=0;j<100;j++)add(i,i+1); 69 for(int j=0;j<100;j++)add(n,1); 70 }else{ 71 for(int i=1;i<=n;i++)b[i]=(node){i,a[i]-tar}; 72 sort(b+1,b+1+n,cmp); 73 74 int su=0; 75 for(int i=1;i<=n;i++)su+=b[i].v; 76 77 if(su%2==1){ 78 add(b[1].i,b[2].i,b[3].i); 79 b[1].v--;b[2].v--;b[3].v--; 80 sort(b+1,b+1+n,cmp); 81 } 82 83 while(b[1].v){ 84 add(b[1].i,b[2].i); 85 b[1].v--; 86 b[2].v--; 87 sort(b+1,b+1+n,cmp); 88 } 89 } 90 cout<<outp.size()<<endl; 91 for(int i=0;i<outp.size();i++){ 92 cout<<outp[i]<<endl; 93 } 94 } 95 96 int main(void) 97 { 98 scanf("%d",&n); 99 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 100 int l=0,r=100;for(int i=1;i<=n;i++)if(a[i]<r)r=a[i]; 101 while(l<=r){ 102 int m=l+r>>1; 103 if(check(m))l=m+1; 104 else r=m-1; 105 } 106 out(r); 107 return 0; 108 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016年10月24日 星期一 17时20分20秒 4 **Problem** : cf730b.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef long long ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 1e5 + 13; 32 33 bool com(int i,int j){ 34 cout<<"? "<<i<<" "<<j<<endl; 35 char c; 36 cin>>c; 37 return c=='<'; 38 } 39 int t,n; 40 int main(void) 41 { 42 cin>>t; 43 while(t--){ 44 cin>>n; 45 int ma,mi; 46 if(n%2==1) 47 ma=mi=1; 48 else 49 if(com(1,2)) mi=1,ma=2; 50 else mi=2,ma=1; 51 52 for(int i=n%2==1?2:3;i<=n;i+=2){ 53 if(com(i,i+1)){ 54 if(com(i,mi))mi=i; 55 if(com(ma,i+1))ma=i+1; 56 }else{ 57 if(com(i+1,mi))mi=i+1; 58 if(com(ma,i))ma=i; 59 } 60 } 61 cout<<"! "<<mi<<" "<<ma<<endl; 62 } 63 return 0; 64 }
C.Bulmart
给1个n点m边简单图(可能不是联通分量),每条边一样长度(就说花费时间一样),一些边上有商店,第i个商店放ci点,有价格pi的ki个货物,q次询问,目的地gi需要ri个货物且不能花超过ai,求能否满足此询问,能的话求出最小的运送最长时间
一开始想用网络流做的,发现其实只是取多个最小值问题就直接转问题思路。做法是对每次询问,从目的地跑bfs,把对应位置商店置一下距离,二分路程求最小路程可满足需求
为了在找到解时直接return,预处理时商店列表以单价递增的方式排序
这里有个问题,就是询问这里是o(qwlogn)+o(qw),1000*5000*12=6*10^7,可能1500ms不能满足,而且@Deep♂Dark♂Fantasy ,为什么你们是o(qwlogn)+o(nw)的还能过?
补:ACdream回答是CF 1s=2~3*10^8次运算,所以能过,顺带HDU 1s=10^8次运算
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016年10月25日 星期二 15时44分33秒 4 **Problem** : cf730c.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef __int64 ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 5e3 + 13; 32 33 int n,m; 34 int w,u,v,q,r,g,a; 35 vector<int> to[maxn]; 36 queue<int> que; 37 int dist[maxn][maxn]; 38 struct St{ 39 ll c,k,p; 40 }st[maxn]; 41 vector<struct St>tt; 42 bool cmp(struct St a,struct St b){ 43 return a.p<b.p; 44 } 45 void bfs(int beg) 46 { 47 memset(dist[beg],-1,sizeof(dist[beg])); 48 dist[beg][beg]=0; 49 que.push(beg); 50 while(!que.empty()){ 51 int te=que.front();que.pop(); 52 for(int i=0;i<to[te].size();i++){ 53 int nex=to[te][i]; 54 if(dist[beg][nex]==-1){ 55 dist[beg][nex]=dist[beg][te]+1; 56 que.push(nex); 57 } 58 } 59 } 60 } 61 bool check(int beg,int dis,int rr,int aa) 62 { 63 tt.clear(); 64 for(int i=1;i<=w;i++) 65 if(dist[beg][st[i].c]<=dis&&dist[beg][st[i].c]!=-1) 66 tt.push_back(st[i]); 67 ll num=0,ans=0; 68 for(int i=0;i<tt.size();i++){ 69 if((tt[i].k+num)<=rr)num+=tt[i].k,ans+=tt[i].k*tt[i].p; 70 else ans+=(rr-num)*tt[i].p,num=rr; 71 if(num==rr&&ans<=aa)return true; 72 } 73 return false; 74 } 75 int main(void) 76 { 77 scanf("%d%d",&n,&m); 78 for(int i=1;i<=m;i++){ 79 scanf("%d%d",&u,&v); 80 to[u].push_back(v); 81 to[v].push_back(u); 82 } 83 for(int i=1;i<=n;i++){bfs(i);} 84 scanf("%d",&w); 85 for(int i=1;i<=w;i++) 86 scanf("%I64d%I64d%I64d",&st[i].c,&st[i].k,&st[i].p); 87 sort(st+1,st+1+w,cmp); 88 scanf("%d",&q); 89 while(q--){ 90 scanf("%d%d%d",&g,&r,&a); 91 int ll=0,rr=n,mid,ans=-1; 92 while(ll<=rr){ 93 mid=(ll+rr)>>1; 94 if(check(g,mid,r,a))ans=mid,rr=mid-1; 95 else ll=mid+1; 96 } 97 printf("%d\n",ans); 98 } 99 return 0; 100 }
D.running over the bridge
有n座桥,每座桥si长,人走在上面后ti秒就倒,人的速度是0.5,有无限瓶能量饮料,喝一瓶可以在r秒内变成1速度,但是只能在整数时点喝,且不能在效果持续时喝(T时喝,T+ti时可以再喝,中间不可以喝)
xjb贪心,把喝饮料的开始时间尽量延迟,然后二分推
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016年10月28日 星期五 09时48分11秒 4 **Problem** : cf730d.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef __int64 ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 2e5 + 13; 32 33 ll n,r; 34 ll l[maxn],t[maxn]; 35 queue<ll>q; 36 int main(void) 37 { 38 scanf("%I64d%I64d",&n,&r); 39 for(int i=1;i<=n;i++)scanf("%I64d",&l[i]); 40 for(int i=1;i<=n;i++)scanf("%I64d",&t[i]); 41 ll mt=0,ans=0,tt=0; 42 for(int i=1;i<=n;i++){ 43 if(l[i]>t[i]){printf("-1\n");return 0;} 44 if(2*l[i]<=t[i]){ 45 if(mt)tt+=mt>l[i]?l[i]:l[i]*2-mt,mt=mt>l[i]?mt-l[i]:0; 46 else tt+=l[i]*2; 47 continue; 48 }//don't have to jiasu 49 ll te=2*l[i]-t[i];//need to add speed. mt:the add rest 50 if(mt>=te){tt+=mt>l[i]?l[i]:(l[i]*2-mt);mt=mt>l[i]?mt-l[i]:0;continue;} 51 else if(mt!=0){tt+=mt;l[i]-=mt;t[i]-=mt;i--;mt=0;continue;} 52 else{ 53 ll a=te/r,b=te%r; 54 ans+=b==0?a:a+1; 55 if(ans<=100000) 56 for(ll j=tt+(l[i]-te)*2;j<tt+t[i];j+=r)q.push(j); 57 tt+=l[i]*2-te; 58 mt=b==0?0:(a+1)*r-te; 59 } 60 } 61 printf("%I64d\n",ans);if(ans>100000)return 0; 62 while(!q.empty()){printf("%I64d ",q.front());q.pop();} 63 return 0; 64 }
E.award ceremony
在另外一个世界,icpc比赛的排序方式是:分数高的排位高,其次id值小的排位高。并且,最后1小时也会封榜,最后才揭晓真正排名,一个个队改变排名
问:如何安排各个队的分数改变顺序,使排名变化次数较多?(点数最多100)
起初我想用树状数组的方法,就是把2组状态集合到一起排序,然后每次贪心移动。
但是一直都没法让数据与我的想法对接
看到一些人的思路才“na ru ho do”每对点的影响都要算和,对答案贡献:点对间如果没有交叉是0,包含关系或交叉但是增减方向相反的肯定是1,交叉并且增减方向相同就是2
这样就轻易出解了。。。白纠结那么久
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016年10月29日 星期六 10时49分45秒 4 **Problem** : cf730e.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef long long ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 200; 32 33 struct node{ 34 int num,ran,add; 35 bool operator < (const node &a)const{ 36 return num>a.num||(num==a.num&&ran<a.ran); 37 } 38 }a[maxn]; 39 int ok(int i,int j){ 40 node x=a[i],y=a[j],xx=x,yy=y; 41 xx.num+=x.add,yy.num+=y.add; 42 if(x<y&&yy<xx)return 1; 43 if(y<x&&xx<yy)return 1; 44 if(x<y&&y<xx&&xx<yy)return 2; 45 if(y<x&&x<yy&&yy<xx)return 2; 46 if(yy<xx&&xx<y&&y<x)return 2; 47 if(xx<yy&&yy<x&&x<y)return 2; 48 return 0; 49 } 50 int main(void) 51 { 52 int n,ans=0; 53 scanf("%d",&n); 54 for(int i=1;i<=n;i++)scanf("%d %d",&a[i].num,&a[i].add),a[i].ran=i; 55 for(int i=1;i<=n;i++){ 56 for(int j=i+1;j<=n;j++){ 57 ans+=ok(i,j); 58 } 59 } 60 printf("%d\n",ans); 61 return 0; 62 }
题意:n天在饭馆吃饭,第i天花费cost(i),奖券最多使用floor(cost(i)/2),使用奖券p点,可以省p元,得到floor((a(i)-p)/10)点奖券,问如何使用可以最大化优惠
之前一直想用o(nlogn)贪心做,从左到右,发现思路太过复杂,把优惠尽量往后推,但是发现如果用除法得到优惠点数,思路比较麻烦
右边的不仅要加1点,要是剩余奖券积了10张还要再处理
剩余的还要再往左遍历一遍,把最大的零头用奖券处理
后来发现不用这么麻烦,消费请求组什么的不用看做1个数字,而是多个数据放到列表来处理
遍历顺序也不正着来,反着来的话,可以把优惠尽量往后推
也不用考虑剩余奖券的问题,因为昨天不能用今天可以用的奖券,直接无视,只保存消费请求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<vector> #include<algorithm> using namespace std; int n, coin, money; int a[5555]; int expire[5555]; vector<int> fre, locked[11]; int ans[5555]; void add_fre(int amount, int id) { for(int i=0;i<amount;i++) fre.push_back(id); } void try_spend_fre(int &amount) { while(amount && fre.size()) { ans[fre.back()] ++; amount --; fre.pop_back(); } } void try_spend(int &amount) { try_spend_fre(amount); for(int i=10;i>0 && amount;i--) while(amount && locked[i].size()) { amount --; int id = locked[i].back(); locked[i].pop_back(); add_fre(i, id); try_spend_fre(amount); } } int main() { scanf("%d%d", &n, &coin); money = 0; for(int i=1;i<=n;i++) { scanf("%d", &a[i]); // 先佯装全额付账,攒冥币.. int today_coin = a[i] / 10; expire[i+1] = today_coin; // 今天挣了多少个币,这些币反着for时第i+1天不用就没得用了 money += a[i]; } for(int i=n;i>0;i--) { int today_discount = a[i]/2; // 大if出没注意!!如果第i+1天有剩余的钱,今天虽然没法花,但是相应的锁也不必加了。 // 这个情况包含了最后一天花不出去的情况。 int lock_fre = expire[i+1]; // 付了也没法多得到冥币的零头,一开始就没锁定 int today_fre = min(a[i]%10, today_discount); add_fre(today_fre, i); today_discount -= today_fre; // 需要花1个冥币才能解锁的部分 for(int j=today_discount / 10; j>0; j--) if (lock_fre) { lock_fre --; add_fre(10, i); } else locked[10].push_back(i); today_discount %= 10; if (today_discount) { if (lock_fre) add_fre(today_discount, i); else locked[today_discount].push_back(i); } try_spend(expire[i]); // 尝试把今天过期的币用掉 } try_spend(coin); for(int i=1;i<=n;i++) money -= ans[i]; printf("%d\n", money); for(int i=1;i<=n;i++) printf("%d%c", ans[i], i<n ? ' ' : '\n'); return 0; }
顺带来一发未完成的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <cstring> #include <fstream> using namespace std; typedef __int64 ll; const int N=5030; int min(int a,int b){return a<b?a:b;} int a[N],b[N]; int main() { int n,bon,i,sum=0; scanf("%d%d",&n,&bon); for(i=0;i<n;i++) { scanf("%d",a+i); int lim=a[i]/2; int m10=(lim-a[i]%10)/10;//the most bonus*10 if(bon<a[i]%10)b[i]=0; else b[i]=a[i]%10+min(m10,(bon-a[i]%10)/10)*10; bon-=b[i]; if(i!=0) { while(b[i-1]>=10 && lim>=b[i]+10) { b[i-1]-=10; b[i]+=10; bon++; if(bon==10 && lim>=b[i]-10) bon-=10,b[i]+=10; } } bon+=(a[i]-b[i])/10; } int proc=bon; bon-=(a[n-1]-b[n-1])/10; int min1=bon,spe=min(bon,a[n-1]/2-a[n-1]+b[n-1]); b[n-1]+=spe; bon-=spe; spe=0; for(i=n-2;i>=0;i--) { bon+= } for(i=0;i<n;i++)sum+=a[i]-b[i]; printf("%d\n",sum); for(i=0;i<n;i++)printf("%d%c",b[i],i!=n-1?' ':'\n'); return 0; }
G. Car Repair Shop
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#pragma warning(disable:4996) #include<iostream> #include<cstdio> #include <algorithm> #include <string.h> #include <queue> #include <vector> #include <stack> #include <set> #include <list> using namespace std; const int maxn = 100100; #define ll long long int main() { int n; scanf("%d", &n); int s[205], d[205]; for (int i = 0;i < n;i++) { scanf("%d%d", &s[i], &d[i]); bool change = false; for (int j = 0;j < i;j++) { if (!((s[i] + d[i] <= s[j]) || (s[i] >= s[j] + d[j]))) { if (change == false) { s[i] = 1; j = -1; change = true; } else { s[i] = s[j] + d[j]; j = -1; } } } printf("%d %d\n", s[i], s[i] + d[i] - 1); } return 0; }
H.Delete Them
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016年10月24日 星期一 16时41分41秒 4 **Problem** : cf730h.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef long long ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 110; 32 33 int n,m; 34 char s[maxn][maxn]; 35 char t[maxn]; 36 int nu[maxn],len[maxn]; 37 bool vis[maxn]; 38 bool match(int v) 39 { 40 int c=strlen(s[v]); 41 if(c!=len[0])return 0; 42 for(int i=0;i<len[0];i++){ 43 if(t[i]!='?'&&t[i]!=s[v][i])return 0; 44 } 45 return 1; 46 } 47 int main(void) 48 { 49 scanf("%d%d",&n,&m); 50 for(int i=0;i<n;i++)scanf("%s",s[i]); 51 for(int i=0;i<m;i++)scanf("%d",&nu[i]),nu[i]--,vis[nu[i]]=true; 52 for(int i=0;i<m;i++){ 53 len[i]=strlen(s[nu[i]]); 54 if(len[i]!=len[0]){ 55 printf("No\n");return 0; 56 } 57 } 58 for(int i=0;i<len[0];i++){ 59 t[i]=s[nu[0]][i]; 60 for(int j=0;j<m;j++){ 61 if(t[i]!=s[nu[j]][i])t[i]='?'; 62 } 63 } 64 for(int i=0;i<n;i++) 65 if(!vis[i]) 66 if(match(i)){ 67 printf("No\n");return 0; 68 } 69 t[len[0]]='\0'; 70 printf("Yes\n%s\n",t); 71 return 0; 72 }
I.Olympiad in Programming and Sports
思路:本题的关键在于建图,由源点连接到p点以及s点容量为p以及s,p点以及s点连接n个点,花费为a[]或者b[],再由这n个点连接汇点,然后直接跑网络模板
当然也可以用基础值+差分化+贪心过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************ 2 *Author* : Ray(siludose) 3 *Created Time* : 2016年10月27日 星期四 20时17分23秒 4 **Problem** : cf730i_flow.cpp 5 **Analyse** : 6 **Get** : 7 **Code** : 8 *********************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 #include <vector> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <string> 19 #include <cmath> 20 #include <cstdlib> 21 #include <ctime> 22 #include <stack> 23 using namespace std; 24 typedef pair<int, int> pii; 25 typedef long long ll; 26 typedef unsigned long long ull; 27 #define pri(a) printf("%d\n",(a)) 28 #define xx first 29 #define yy second 30 const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; 31 const int maxn = 5e4 + 13; 32 const int maxm=300000; 33 struct Edge{ 34 int to,next,cap,flow,cost; 35 }edge[maxm]; 36 int head[maxn],tol; 37 int pre[maxn],dis[maxn]; 38 bool vis[maxn]; 39 int N; 40 void init(int n) 41 { 42 N=n; 43 tol=0; 44 memset(head,-1,sizeof(head)); 45 } 46 void addedge(int u,int v,int cap,int cost) 47 { 48 edge[tol].to=v; 49 edge[tol].cap=cap; 50 edge[tol].cost=cost; 51 edge[tol].flow=0; 52 edge[tol].next=head[u]; 53 head[u]=tol++; 54 edge[tol].to=u; 55 edge[tol].cap=0; 56 edge[tol].cost=-cost; 57 edge[tol].flow=0; 58 edge[tol].next=head[v]; 59 head[v]=tol++; 60 } 61 bool spfa(int s,int t) 62 { 63 queue<int>q; 64 for(int i=0;i<N;i++){ 65 dis[i]=INF; 66 vis[i]=false; 67 pre[i]=-1; 68 } 69 dis[s]=0; 70 vis[s]=true; 71 q.push(s); 72 while(!q.empty()){ 73 int u=q.front(); 74 q.pop(); 75 vis[u]=false; 76 for(int i=head[u];i!=-1;i=edge[i].next){ 77 int v=edge[i].to; 78 if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost){ 79 dis[v]=dis[u]+edge[i].cost; 80 pre[v]=i; 81 if(!vis[v]){ 82 vis[v]=true; 83 q.push(v); 84 } 85 } 86 } 87 } 88 if(pre[t]==-1)return false; 89 else return true; 90 } 91 ll minCostMaxflow(int s,int t){ 92 ll flow=0; 93 ll cost=0; 94 while(spfa(s,t)){ 95 int Min=INF; 96 for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ 97 if(Min>edge[i].cap-edge[i].flow) 98 Min=edge[i].cap-edge[i].flow; 99 } 100 for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ 101 edge[i].flow+=Min; 102 edge[i^1].flow-=Min; 103 cost+=edge[i].cost*Min; 104 } 105 flow+=Min; 106 } 107 return cost; 108 } 109 int a[maxn],b[maxn]; 110 vector<int>aa,bb; 111 int main(void) 112 { 113 int n,p,s; 114 scanf("%d%d%d",&n,&p,&s); 115 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 116 for(int i=1;i<=n;i++)scanf("%d",&b[i]); 117 init(n+4); 118 for(int i=1;i<=n;i++){ 119 addedge(0,i,1,0); 120 addedge(i,n+1,1,-a[i]); 121 } 122 for(int i=1;i<=n;i++){ 123 addedge(i,n+2,1,-b[i]); 124 } 125 addedge(n+1,n+3,p,0); 126 addedge(n+2,n+3,s,0); 127 printf("%lld\n",-minCostMaxflow(0,N-1)); 128 for (int u = 1; u <= n; u++){ 129 for(int i=head[u];i!=-1;i=edge[i].next){ 130 int v=edge[i].to; 131 if(!edge[i].flow)continue; 132 if(v==(n+1))aa.push_back(u); 133 if(v==(n+2))bb.push_back(u); 134 } 135 } 136 int sz=aa.size(); 137 for(int i=0;i<sz;i++)printf("%d%c",aa[i],i==(sz-1)?'\n':' '); 138 sz=bb.size(); 139 for(int i=0;i<sz;i++)printf("%d%c",bb[i],i==(sz-1)?'\n':' '); 140 return 0; 141 }
J.Bottles
给n个瓶子,容量bi剩余ai液体,在把所有液体合到最少瓶子的前提下液体转移最少,问最后有液体瓶子数量和转移液体量
发现转移液体量就是几个瓶子剩下的液体量,可以先贪心一波把液体一起倒在容量最大的几个瓶,发现还有某些情况会让贪心失效(容量大,剩余小)
不够这个步骤可以确定最少用几个瓶
一开始想到搜索,有序性搜索元素。然而100个瓶子,剪枝了都不够
计算过程发现可以把几个状态按照第几个瓶子(按容量递减剩余递减排序)总容量和实际选中瓶子数合并状态数
然后就愉快地dp了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/************************************************ *Author* : Ray(siludose) *Created Time* : 2016年10月26日 星期三 19时27分49秒 **Problem** : cf730f.cpp **Analyse** : **Get** : **Code** : *********************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> #include <stack> using namespace std; typedef pair<int, int> pii; typedef long long ll; typedef unsigned long long ull; #define pri(a) printf("%d\n",(a)) #define xx first #define yy second const int mod = int(1e9) + 7, INF = 0x3f3f3f3f; const int maxn = 100 + 13; int dp[maxn][21000]; int an[maxn][21000]; int n,a[maxn],b[maxn]; int main(void) { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&b[i]); memset(dp,0x3f,sizeof(dp)); memset(an,0x3f,sizeof(an)); int kk=10000;dp[0][kk]=0;an[0][kk]=0; for(int i=1;i<=n;i++){ for(int j=0;j<=20100;j++){ if(dp[i][j-a[i]]>dp[i-1][j]){ dp[i][j-a[i]]=dp[i-1][j]; an[i][j-a[i]]=an[i-1][j]+a[i]; }else if(dp[i][j-a[i]]==dp[i-1][j]){ an[i][j-a[i]]=min(an[i][j-a[i]],an[i-1][j]+a[i]); } if(dp[i][j+b[i]-a[i]]>dp[i-1][j]+1){ dp[i][j+b[i]-a[i]]=dp[i-1][j]+1; an[i][j+b[i]-a[i]]=an[i-1][j]; }else if(dp[i][j+b[i]-a[i]]==dp[i-1][j]+1){ an[i][j+b[i]-a[i]]=min(an[i][j+b[i]-a[i]],an[i-1][j]); } } } int ans=0x3f3f3f3f; int num=0x3f3f3f3f; for(int i=10000;i<=20100;i++){ if(dp[n][i]<ans){ ans=dp[n][i];num=an[n][i]; }else if(dp[n][i]==ans){ num=min(num,an[n][i]); } } printf("%d %d\n",ans,num); return 0; }
一个联通无向图(最多400000个点,1000000条边)把所有边改成有向边,使s点为唯一源点,t为唯一汇点,且没有有向环
唯一源点和汇点判断比较容易,从s点dfs一次求各点深度,求出dep(深度)表和fa(祖先)表,t点bfs一次,边有没走2次的就是不唯一
难点在于如何让路径变成没有有向环
画几个图就会发现,环上1、2条链且源点汇点属于不同树时可以构造无环路,多了会变成不唯一源点汇点
其他类似的例如8字形的图因为不存在分叉的情况(有的话遍历2次后直接筛出来了),且有时从源点到汇点的路径不会走到与环相切的位置
此外环上有树(或者说从源点到汇点的路径会走到与环相切的位置)会让路径一定出现有向环(2个点属于相同树)/源点汇点不唯一(2个点属于不同树)
想到这一步就没有思路了。。。感谢codeforces的开源机制,让我理解了那些大神的做法
碰到非树边(遍历图时边没走,目标点也没走的情况就是树边,这里是指边没走,目标点走过了)在另一个图建立映射图映射本体图
建立映射边是建son(v)->u不是v->u
因为可能v是源点,而画必经之路是从深度大的遍历完再走深度小的,如果v->u会因为fa[u]=-1有一些本该标记的边不会被标记
这样如果碰到从源点到汇点的路径会走到与环相切位置的情况时,映射图的边是映射在非必经之路上的(从汇点沿fa表走不到环边),不影响结果
没有分叉且不会走到与环相切的点,映射图的边会映射到另一条必经之路,再沿fa表走,填满另一条路
之后遍历对应无向边,全部都是必经之路就是有解
最后SB了,把边的数组大小开成点的数据大小,结果WA17...改了之后马上AC
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#pragma comment(linker, "/STACK:102400000,102400000") #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cassert> #include <ctime> #include <cstring> #include <fstream> using namespace std; typedef __int64 ll; const int V=400005; const int E=2000005; int to0[E],to1[E],id0[E],id1[E],nxt0[E],nxt1[E]; int head0[V],head1[V],cnt0,cnt1,n; int fa[V],son[V],dep[V],edg[V]; bool vis[V]; void addedge(int u,int v,int edgeid) { to0[cnt0]=v;id0[cnt0]=edgeid;nxt0[cnt0]=head0[u];head0[u]=cnt0++; to0[cnt0]=u;id0[cnt0]=edgeid;nxt0[cnt0]=head0[v];head0[v]=cnt0++; } void adde(int u,int v,int edgeid) { to1[cnt1]=v;id1[cnt1]=edgeid;nxt1[cnt1]=head1[u];head1[u]=cnt1++; } void dfs(int s,int depth) { //printf("\r%d",s); assert(depth<=n+3); assert(s<=n); vis[s]=true; for(int i=head0[s];i!=-1;i=nxt0[i]) { int v=to0[i]; assert(v<=n); if(v==fa[s])continue; if(!vis[v]) { edg[v]=id0[i]; dep[v]=dep[s]+1; son[s]=v; fa[v]=s; dfs(v,depth+1); } else if(dep[v]<dep[s]) adde(son[v],s,id0[i]); } } pair<int,int> que[V<<1]; int dire[E]; void bfs(int t) { int tal=0,hed=0; queue<pair<int,int> > que; que.push(make_pair(t,0)); while(!que.empty()) { pair<int,int> pii=que.front(); int u=pii.first,di=pii.second; que.pop(); while(fa[u]!=-1 && dire[edg[u]]==-1) { assert(u<=n); dire[edg[u]]=di; for(int i=head1[u];i!=-1;i=nxt1[i]) { int v=to1[i]; assert(v<=n); dire[id1[i]]=di; que.push(make_pair(v,di^1)); } u=fa[u]; } } } int tu[E],tv[E]; int main() { //freopen("pro.in","r",stdin); int T,m,s,t,i; scanf("%d",&T); while(T--) { bool flag=false; scanf("%d%d%d%d",&n,&m,&s,&t); memset(dire,-1,sizeof(int)*(m+3)); memset(vis,0,sizeof(bool)*(n+3)); memset(head0,-1,sizeof(int)*(n+3));cnt0=0; memset(head1,-1,sizeof(int)*(n+3));cnt1=0; for(i=0;i<m;i++) { scanf("%d%d",tu+i,tv+i); addedge(tu[i],tv[i],i); } dep[s]=0;fa[s]=-1; dfs(s,0); bfs(t); for(i=0;i<m;i++) { if(dire[i]==-1){flag=true;break;} } if(flag)puts("No"); else { puts("Yes"); for(i=0;i<m;i++) { if((dep[tu[i]]<dep[tv[i]])==dire[i])tu[i]^=tv[i]^=tu[i]^=tv[i]; printf("%d %d\n",tu[i],tv[i]); } } } return 0; }
给一段表达式,每次查询截取区间内表达式,问那段表达式的运算结果,如果不符合表达式的组成规律,输出-1
咋看是个很难缠的线段树题,仔细一看因为不涉及修改,其实线性查询就可以解决
左右各扫一遍,1个括号1个栈元素,不用递归,直接在构造表时推栈
碰到左括号时升栈,碰到右括号时降栈
至于其他3种符号就用类似于2016弱校10.3 J的处理方式
a1表示上一个加号左边的和,a2表示上一个加号右边上一个乘号左边的积,a3表示目前的右边数字,初始a1=0 a2=1 a3=0
碰到数字把a3*10+str[i]-'0'
碰到乘号把a2*=a3,a3=1
碰到加号把a1+=a2*a3,a2=1,a3=0
查询时先看左右是否是'+' '*',左边是否')' 右边是否'('
再匹配括号,看不同位置匹配的括号层数是否一样
完了再组合算式出结果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> typedef __int64 ll; const int xn = 400008; const __int64 MOD = 1000000007; int N, Q, D, pb[xn], pp[xn], pm[xn], sb[xn], sp[xn], sm[xn], Lb[xn], Lp[xn], Lm[xn]; char a[xn]; __int64 P10[xn], iP10[xn], Ab[xn], Ap[xn], Az[xn], Am[xn], ab[xn], ap[xn], az[xn], am[xn], hb[xn], hp[xn], hz[xn], hm[xn], // h?[] and t?[] are not available for i that a[i] == '+' || a[i] == '*' tb[xn], tp[xn], tz[xn], tm[xn]; __int64 INV(__int64 x) { __int64 r = 1; for (__int64 b = MOD - 2; b; b >>= 1) { if (b & 1) r = r * x % MOD; x = x * x % MOD; } return r; } __int64 F(int l, int r) { if (a[l] == '+' || a[l] == '*' || a[l] == ')') return -1; if (a[r] == '+' || a[r] == '*' || a[r] == '(') return -1; if (sb[pb[l]] != sb[r]) return -1; int lep = pp[l], rip = sp[r]; if (sp[lep] != rip) return (hb[r] + tb[l] - ab[pb[l]] + MOD) % MOD; else { int lem = pm[l], rim = sm[r]; if (sm[lem] != rim) return hz[r] + tz[l] == az[pp[l]] ? hp[r] * tp[l] % MOD * INV(ap[pp[l]]) % MOD : 0; else return (hm[r] + (tm[l] - am[pm[l]] + MOD) * iP10[rim - r - 1]) % MOD; } return 0; } int main() { scanf("%s", a + 2); while (a[N + 2]) N++; N += 2; a[1] = '(', a[N] = ')'; iP10[0] = P10[0] = 1; for (int i = 1,l; i <= N; i++) { P10[i] = P10[i - 1] * 10 % MOD; iP10[i] = iP10[i - 1] * 700000005 % MOD; } for (i = 1; i <= N; i++) { if( a[i] == ')') { ab[Lb[D]] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; ap[Lp[D]] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; az[Lp[D]] = Az[D] + !Am[D]; am[Lm[D]] = Am[D]; } pb[i] = Lb[D]; pp[i] = Lp[D]; pm[i] = Lm[D]; if (a[i] == '(') { D++; Lb[D] = Lp[D] = Lm[D] = i; Az[D] = Ab[D] = Am[D] = 0; Ap[D] = 1; } else if (a[i] == '+') { ap[Lp[D]] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; az[Lp[D]] = Az[D] + !Am[D]; am[Lm[D]] = Am[D]; Lp[D] = Lm[D] = i; Ab[D] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; Ap[D] = 1; Az[D] = 0; Am[D] = 0; } else if (a[i] == '*') { am[Lm[D]] = Am[D]; Lm[D] = i; Ap[D] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; Az[D] = Az[D] + !Am[D]; Am[D] = 0; } else if (a[i] >= '0' && a[i] <= '9') { Am[D] = (Am[D] * 10 + a[i] - 48) % MOD; hb[i] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; hp[i] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; hz[i] = Az[D] + !Am[D]; hm[i] = Am[D]; } else { Am[D - 1] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; D--; hb[i] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; hp[i] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; hz[i] = Az[D] + !Am[D]; hm[i] = Am[D]; } } for (i = N, l = -1; i; i--) { if (a[i] >= '0' && a[i] <= '9') l++; else l = -1; sb[i] = Lb[D]; sp[i] = Lp[D]; sm[i] = Lm[D]; if (a[i] == ')') { D++; Lb[D] = Lp[D] = Lm[D] = i; Az[D] = Ab[D] = Am[D] = 0; Ap[D] = 1; } else if (a[i] == '+') { Lp[D] = Lm[D] = i; Ab[D] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; Ap[D] = 1; Az[D] = 0; Am[D] = 0; } else if (a[i] == '*') { Lm[D] = i; Ap[D] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; Az[D] = Az[D] + !Am[D]; Am[D] = 0; } else if (a[i] >= '0' && a[i] <= '9') { Am[D] = (Am[D] + P10[l] * (a[i] - 48)) % MOD; tb[i] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; tp[i] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; tz[i] = Az[D] + !Am[D]; tm[i] = Am[D]; } else { Am[D - 1] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; D--; tb[i] = (Ab[D] + (Az[D] ? 0 : Ap[D]) * Am[D]) % MOD; tp[i] = Ap[D] * (Am[D] ? Am[D] : 1) % MOD; tz[i] = Az[D] + !Am[D]; tm[i] = Am[D]; } } for (scanf("%d", &Q); Q--; ) { int l, r; scanf("%d%d", &l, &r); printf("%I64d\n", F(l + 1, r + 1)); } return 0; }