2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror) in codeforces(codeforces730)

A.Toda 2

思路:可以有二分来得到最后的数值,然后每次排序去掉最大的两个,或者3个(奇数时)。

  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
",(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
",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 }
View Code

B.Minimum and Maximum

 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
",(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 }
View Code

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次运算

  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
",(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
",ans);
 98     }
 99     return 0;
100 }
View Code 

D.running over the bridge

有n座桥,每座桥si长,人走在上面后ti秒就倒,人的速度是0.5,有无限瓶能量饮料,喝一瓶可以在r秒内变成1速度,但是只能在整数时点喝,且不能在效果持续时喝(T时喝,T+ti时可以再喝,中间不可以喝)

xjb贪心,把喝饮料的开始时间尽量延迟,然后二分推

 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
",(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
");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
",ans);if(ans>100000)return 0;
62     while(!q.empty()){printf("%I64d ",q.front());q.pop();}
63     return 0;
64 }
View Code

E.award ceremony

在另外一个世界,icpc比赛的排序方式是:分数高的排位高,其次id值小的排位高。并且,最后1小时也会封榜,最后才揭晓真正排名,一个个队改变排名

问:如何安排各个队的分数改变顺序,使排名变化次数较多?(点数最多100)

起初我想用树状数组的方法,就是把2组状态集合到一起排序,然后每次贪心移动。

但是一直都没法让数据与我的想法对接

看到一些人的思路才“na ru ho do”每对点的影响都要算和,对答案贡献:点对间如果没有交叉是0,包含关系或交叉但是增减方向相反的肯定是1,交叉并且增减方向相同就是2

这样就轻易出解了。。。白纠结那么久

 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
",(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
",ans);
61     return 0;
62 }
View Code

F.Ber Patio

题意:n天在饭馆吃饭,第i天花费cost(i),奖券最多使用floor(cost(i)/2),使用奖券p点,可以省p元,得到floor((a(i)-p)/10)点奖券,问如何使用可以最大化优惠

之前一直想用o(nlogn)贪心做,从左到右,发现思路太过复杂,把优惠尽量往后推,但是发现如果用除法得到优惠点数,思路比较麻烦

右边的不仅要加1点,要是剩余奖券积了10张还要再处理

剩余的还要再往左遍历一遍,把最大的零头用奖券处理

后来发现不用这么麻烦,消费请求组什么的不用看做1个数字,而是多个数据放到列表来处理

遍历顺序也不正着来,反着来的话,可以把优惠尽量往后推

也不用考虑剩余奖券的问题,因为昨天不能用今天可以用的奖券,直接无视,只保存消费请求

#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
", money);
    for(int i=1;i<=n;i++)
        printf("%d%c", ans[i], i<n ? ' ' : '
');
    
    return 0;
}
View Code

顺带来一发未完成的

#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
",sum);
    for(i=0;i<n;i++)printf("%d%c",b[i],i!=n-1?' ':'
');
    return 0;
}
View Code

G. Car Repair Shop

#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
", s[i], s[i] + d[i] - 1);
    }
    return 0;
}
View Code

H.Delete Them

 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
",(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
");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
");return 0;
68             }
69     t[len[0]]='';
70     printf("Yes
%s
",t);
71     return 0;
72 }
View Code

I.Olympiad in Programming and Sports

思路:本题的关键在于建图,由源点连接到p点以及s点容量为p以及s,p点以及s点连接n个点,花费为a[]或者b[],再由这n个点连接汇点,然后直接跑网络模板

当然也可以用基础值+差分化+贪心过

  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
",(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
",-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)?'
':' ');
138     sz=bb.size();
139     for(int i=0;i<sz;i++)printf("%d%c",bb[i],i==(sz-1)?'
':' ');
140     return 0;
141 }
View Code

J.Bottles

给n个瓶子,容量bi剩余ai液体,在把所有液体合到最少瓶子的前提下液体转移最少,问最后有液体瓶子数量和转移液体量

发现转移液体量就是几个瓶子剩下的液体量,可以先贪心一波把液体一起倒在容量最大的几个瓶,发现还有某些情况会让贪心失效(容量大,剩余小)

不够这个步骤可以确定最少用几个瓶

一开始想到搜索,有序性搜索元素。然而100个瓶子,剪枝了都不够

计算过程发现可以把几个状态按照第几个瓶子(按容量递减剩余递减排序)总容量和实际选中瓶子数合并状态数

然后就愉快地dp了

/************************************************
 *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
",(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
",ans,num);
    return 0;
}
View Code

K.Roads Orientation Problem

一个联通无向图(最多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

#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("
%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
",tu[i],tv[i]);
            }
        }
    }
    return 0;
}
View Code

L.Expression Queries

给一段表达式,每次查询截取区间内表达式,问那段表达式的运算结果,如果不符合表达式的组成规律,输出-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

查询时先看左右是否是'+' '*',左边是否')' 右边是否'('

再匹配括号,看不同位置匹配的括号层数是否一样

完了再组合算式出结果

#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
", F(l + 1, r + 1));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/dgutfly/p/5998743.html