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; }
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; }
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; }
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; }
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; }