Codeforces补题2020.2.29 (Round623 Div2)

A.Dead Pixel

作者有一个a*b大小的矩形,但矩形上有一个点(x,y)是污渍。

现在需要你计算出避开污渍的情况下切割出的矩形的最大面积。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1014;
int getArea (int x1,int y1,int x2,int y2,int a,int b) {
    if (x1<0||x1>=a||x2<0||x2>=a||y1<0||y1>=b||y2<0||y2>=b) 
        return 0;
    return (abs(x1-x2)+1)*(abs(y1-y2)+1);
} 
int main () {
    int T;
    int a,b,x,y;
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d%d%d",&a,&b,&x,&y);
        int ans=0;
        ans=max(ans,getArea(0,0,x-1,b-1,a,b));
        ans=max(ans,getArea(0,0,a-1,y-1,a,b));
        ans=max(ans,getArea(x+1,0,a-1,b-1,a,b));
        ans=max(ans,getArea(0,y+1,a-1,b-1,a,b));
        printf ("%d
",ans);
    }
    return 0;
}
View Code

B.Homecoming

经过一个长时间的聚会,佩蒂娅决定回家,但事实证明他就在镇的另一端。镇上有n个十字路口,每个十字路口都有公共汽车站或有轨电车站。

十字路口表示为长度n的字符串s,其中s i=a,如果i-th十字路口有公共汽车站,si=B,如果i-th十字路口有电车站。目前,佩蒂亚在第一个十字路口(对应于s1),他的目标是到达最后一个十字路口(对应于sn)。

如果两个十字路口i和j,所有十字路口i、i+1、…、j-1都有一个公共汽车站,可以支付一卢布的车票,然后从i-th十字路口乘公共汽车到j-th十字路口(不必在j-th十字路口有一个公共汽车站)。从形式上讲,如果st=a表示i≤t<j,支付一卢布佩特雅可以从i转到j。

如果i和j两个十字路口i、i+1、…、j-1都有一个有轨电车站,可以支付b卢布的有轨电车车票,然后从i-th十字路口乘有轨电车到j-th十字路口(无需在j-th十字路口有轨电车站)。从形式上讲,如果st=b表示所有i≤t<j,那么支付b卢布Petya可以从i转到j。

例如,如果s=“AABBBAB”,a=4和b=3,那么Petya需要:

买一张1到3的巴士票,

买一张3点到6点的有轨电车票,

买一张6点到7点的公共汽车票。

因此,他总共需要花费4+3+4=11卢布。请注意,最后一个十字路口的停车类型(即字符sn)不影响最终费用。

现在佩蒂亚在第一个十字路口,他想去第n个十字路口。晚会结束后他带着卢布离开了。他决定步行去某个车站,然后只用公共交通工具回家。

帮他选一个最近的十字路口,我先步行去,这样他就有足够的钱从第一个十字路口到第n个十字路口,只用电车和公共汽车票。

输入

每个测试包含一个或多个测试用例。第一行包含测试用例的数量t(1≤t≤104)。

每个测试用例的第一行由三个整数a、b、p(1≤a、b、p≤105)-公车票成本、电车票成本和Petya拥有的金额组成。

每个测试用例的第二行由一个字符串s组成,其中s i=A,如果i-th crossroad有公共汽车站,si=B,如果i-th crossroad有电车站(2≤| s |≤105)。

保证一次测试中所有测试用例的字符串长度之和不超过105。

输出

对于每个测试用例,打印一个数字——一个十字路口Petya的最小索引i应该步行。剩下的路(即从i到n他应该使用公共交通工具)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1014;
int a,b,p;
string s;
int main () {
    int T;
    int a,b,p;
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d%d",&a,&b,&p);
        cin>>s;
        int i;
        for (i=s.length()-2;i>=0;i--) {
            if (s[i]=='A') {
                if (p<a) break;
                p-=a;
            }
            if (s[i]=='B') {
                if (p<b) break;
                p-=b;
            }
            while (i>0&&s[i]==s[i-1]) i--;
        }
        printf ("%d
",i+2);
    }
    return 0;
}
View Code

C.Restoring Permutation

给你一个序列b1,b2,…,bn。找到字典上最小的排列a1,a2,…,a2n,使得bi=min(a2i-1,a2i),或者确定它是不可能的。

输入

每个测试包含一个或多个测试用例。第一行包含测试用例的数量t(1≤t≤100)。

每个测试用例的第一行由一个整数n-序列b中的元素数(1≤n≤100)组成。

每个测试用例的第二行包含n个不同的整数b1,…,bn-序列b的元素(1≤bi≤2n)。

保证所有测试用例的n之和不超过100。

输出

对于每个测试用例,如果没有合适的排列,则打印一个数字-1。

否则,打印2n整数a1,…,a2n-从1到2n的数字的字典最小置换。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1014;
int N;
int a[maxn];
int visit[maxn];
int h[maxn];
void solve () {
    memset(h,0,sizeof(h));
    memset(visit,0,sizeof(visit));
    scanf("%d",&N);
    for (int i=0;i<N;i++) {
        scanf("%d",&a[i*2+1]);
        h[a[i*2+1]]=i*2+1;
        visit[a[i*2+1]]=1;
    }
    int now=1;
    for (int i=1;i<=2*N;i++) {
        if (!h[i]) {
            printf ("-1
");
            return;
        }
        if (!visit[i]) continue;
        for (int j=i+1;j<=2*N;j++) {
            if (!h[j]) {
                a[h[i]+1]=j;
                h[j]=h[i]+1;
                break;
            }
        }
    }
    for (int i=1;i<=N;i++) {
        for (int j=i+1;j<=N;j++) {
            if (a[i*2]>=a[j*2-1]&&a[j*2]>=a[i*2-1]&&a[j*2]<a[i*2]) {
                swap(a[i*2],a[j*2]);
            }
        }
    }
    for (int i=1;i<=2*N;i++) 
        printf ("%d ",a[i]);
}
int main () {
    int T;
    scanf("%d",&T);
    while (T--) solve();
    return 0;
}
View Code

D.Recommendations

给出一个序列,只能对序列里的元素进行+1的操作,每个元素+1的代价都不相同。计算使得序列里每个元素互不相同的最小代价。

include<bits/stdc++.h>
using namespace std;
const int maxn=1014;
typedef long long ll;
int N;
int main () {
    scanf("%d",&N);
    vector<pair<int,int>> vi(N);
    for (int i=0;i<N;i++) scanf("%d",&vi[i].first);
    for (int i=0;i<N;i++) scanf("%d",&vi[i].second);
    sort (vi.begin(),vi.end());
    ll ans=0;
    for (int i=0;i<N;) {
        priority_queue<int> q;
        q.push(vi[i].second);
        ll sum=vi[i].second;
        int cur=vi[i].first;
        int j=i+1;
        while (1) {
            while (j<N&&vi[j].first==cur) {
                q.push(vi[j].second);
                sum+=vi[j++].second;
            }
            if (q.size()==1) break;
            sum-=q.top();
            ans+=sum;
            q.pop();
            cur++;
        } 
        i=j;
    }
    printf ("%lld
",ans);
    return 0;
}
View Code

E.Double Elimination

辩论赛采取的是双败赛制,下面介绍一下双败赛制(即使您已经知道是怎么回事也请务必读完题面):

1.参赛队伍从1到2的n次方编号,将进行一对一的比赛。所有的队伍都从胜者组开始。

2.所有的胜者组比赛将在尚未输掉任何比赛的球队之间进行。球队按队数分组比赛,赢家晋级下一轮胜者组,输家则进入败者组。起初1和2打,3和4打,5和6打,7和8打...,然后1和2打完胜利的 和 3和4打完胜利的再打一场,1和2打完失败的和3和4打完失败的也再打一场,然后,失败组最终胜利的和胜利组最终胜利的再打一场。

现在,您有一个喜欢的队伍的名单,您可以猜测比赛的输赢。请您计算在所有可能的比赛进程中,有您喜欢的队伍参加的比赛的最大场次。

为了使您更方便理解,举个例子。一共有4支队伍,编号1,2,3,4。您喜欢的队伍是1和4。第一轮1和2打,3和4打,1,3号队伍胜出,2,4进入败者组,第二轮1和3打,2和4打,3,4胜出,那么最后的决赛就是3和4打,在这个过程中有1、4参加的比赛有5场。

输入

第一行输入两个整数N和K,分别代表有N支队伍参加比赛,有K个队伍是你喜欢的。

第二行输入K个整数,代表K支队伍的编号。

输出

输出一个数字,代表有你喜欢的队伍参加的比赛的最大场次。

#include<bits/stdc++.h>
using namespace std;
const int maxn=((1<<17)+1014);
int N,K;
int a[maxn];
int dp[18][maxn][2][2];
//dp[i][j][x1][y1]表示从j开始,连续的2^(i)个人比赛,
//胜利组胜出的人是不是(1/0)你喜欢的队
//失败组胜出的人是不是(1/0)你喜欢的队
// dp数组的值表示你喜欢的队伍目前参与了多少场比赛 
void init () {
    //初始化,把所有的DP值全部初始化为负无穷 
    for (int i=0;i<18;i++) {
        for (int j=0;j<maxn;j++) {
            for (int k=0;k<2;k++) {
                for (int z=0;z<2;z++) {
                    dp[i][j][k][z]=-1e9;
                }
            }
        }
    }
} 
int main () {
    init ();
    scanf("%d%d",&N,&K);
    for (int i=0;i<K;i++) {
        int x;
        scanf("%d",&x);
        a[x-1]=1;//统一把编号往前挪一位 
    }
    for (int i=1;i<=N;i++) {
        //i从1开始加到N,不断倍增,就是一个从第一轮比赛推到最后一轮决赛的过程 
        for (int j=0;j<(1<<N);j+=(1<<i)) {
            //2^i支队伍为一组,遍历每一组队伍 
            if (i==1) { 
            //如果只有两支队伍,特殊处理,此时只有胜者组 
                for (int x1=0;x1<2;x1++) {
                    for (int y1=0;y1<2;y1++) {
                        if (x1+y1==a[j]+a[j+1]) 
                            dp[i][j][x1][y1]=((a[j]+a[j+1])>0?1:0);
                        //遍历有比赛情况 
                        //如果两只队伍都是喜欢的队伍,那就一定都会进入下一轮(一个胜者组,一个败者组 
                        //如果两只队伍有一支是喜欢的队伍,那么最多只可能有一支喜欢的队伍进入下一轮(胜者组或败者组)
                        //如果两只队伍都不是喜欢的队伍,那么不会有队伍进入下一轮。
                        //dp最后的值是,如果存在喜欢的队伍,那么不管有一支或两支,它们最多也只能参加一场比赛,所以如式子所示 
                    }
                }
            }
            else {
                //有多支队伍,分为胜者组和败者组 
                for (int x1=0;x1<2;x1++) {
                    for (int y1=0;y1<2;y1++) {
                        for (int x2=0;x2<2;x2++) {
                            for (int y2=0;y2<2;y2++) {
                                //遍历上一轮两组队伍的所有的比赛情况 
                                //x1,y1代表胜利组,x2,y2代表失败组 
                                int cost=dp[i-1][j][x1][y1]+dp[i-1][j+(1<<(i-1))][x2][y2];
                                //定义当前你喜欢的队伍参与的比赛数量cost是上一轮的两个组分别的dp值之和 
                                if (x1||x2) cost++;
                                //如果胜者组至少有一个你喜欢的队伍留下来了,那么你喜欢的队伍会参加当前的比赛,cost值加一
                                if (y1||y2) cost++;
                                //如果败者组至少有一个你喜欢的队伍留下了了,那么你喜欢的队伍会参加当前的比赛,cost值加一 
                                //接下来枚举八种比赛状态 
                                dp[i][j][x1][x2]=max(dp[i][j][x1][x2],cost+((x2+y1)>0?1:0)); 
                                dp[i][j][x1][y1]=max(dp[i][j][x1][y1],cost+((x2+y1)>0?1:0));
                                //上一轮比赛胜出的是x1,y1,那么y1会和x2再比一场,y2直接淘汰 
                                dp[i][j][x1][x2]=max(dp[i][j][x1][x2],cost+((x2+y2)>0?1:0));
                                dp[i][j][x1][y2]=max(dp[i][j][x1][y2],cost+((x2+y2)>0?1:0));
                                //上一轮比赛胜出的是x1,y2,那么y2会和x2再比一场,y1直接淘汰 
                                dp[i][j][x2][x1]=max(dp[i][j][x2][x1],cost+((x1+y2)>0?1:0));
                                dp[i][j][x2][y2]=max(dp[i][j][x2][y2],cost+((x1+y2)>0?1:0));
                                //上一轮比赛胜出的是x2,y2,那么x1会和y2再比一场,y1直接淘汰 
                                dp[i][j][x2][x1]=max(dp[i][j][x2][x1],cost+((x1+y1)>0?1:0));
                                dp[i][j][x2][y1]=max(dp[i][j][x2][y1],cost+((x1+y1)>0?1:0));
                            }   //上一轮比赛胜出的是x2,y1,那么x1会和y1再比一场,y2直接淘汰 
                        }
                    }
                }
            }
        }
    }
    int ans=0;
    for (int i=0;i<2;i++) {
        for (int j=0;j<2;j++) {
            int cost=dp[N][0][i][j];
            //cost表示2^N支队伍遍历完,比赛结束的四种比赛状态 
            if (i+j) cost++;//如果存在喜欢的队伍,就把决赛也算进去 
            ans=max(ans,cost);
        }
    }
    printf ("%d
",ans);
    return 0;
}
View Code

 

原文地址:https://www.cnblogs.com/zhanglichen/p/12386545.html