A. Cut the Triangle
题目链接:Problem - A - Codeforces
样例输入:
4
4 7
6 8
3 5
4 5
4 7
6 8
5 8
1 8
2 5
3 6
6 6
6 3
样例输出:
YES
YES
YES
NO
题意:在二维平面上给定一个非退化三角形的三个顶点,问我们能不能用一条平行或者垂直于坐标轴的直线将这个非退化三角形分成两个非退化三角形,非退化三角形代表这个三角形的面积是一个正数。
分析:只要这个三角形不是一个两条直角边分别平行于横纵坐标轴的直角三角形即可。转化为数学式就是只要找到一个点的横坐标或者纵坐标位于另外两个点的横坐标或者纵坐标之间(不能相等)即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
struct node{
int x,y;
}p[5];
bool cmp1(node a,node b)
{
return a.x<b.x;
}
bool cmp2(node a,node b)
{
return a.y<b.y;
}
int main()
{
int T;
cin>>T;
while(T--)
{
for(int i=1;i<=3;i++)
scanf("%d %d",&p[i].x,&p[i].y);
sort(p+1,p+4,cmp1);
if(p[2].x<p[3].x&&p[2].x>p[1].x)
{
puts("YES");
continue;
}
sort(p+1,p+4,cmp2);
if(p[2].y<p[3].y&&p[2].y>p[1].y)
{
puts("YES");
continue;
}
puts("NO");
}
return 0;
}
B. Block Towers
题目链接:Problem - B - Codeforces
样例输入:
4
3
1 2 3
3
1 2 2
2
1 1000000000
10
3 8 6 7 4 1 2 4 10 1
样例输出:
3
2
500000001
9
题意:给定n个整数a[],分别代表楼塔的高度,我们可以对这些楼塔进行操作,每次操作可以选择两个楼塔i和j,如果a[i]>a[j],那么可以让a[i]-1,a[j]+1。问我们最多能让第一个楼塔的高度达到多高?
分析:直接贪心考虑即可,先将第2~n座楼塔按照高度进行从小到大排序,然后从第二个楼塔开始,依次往第一座楼塔上增加高度,直至操作完所有的楼塔即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=2e5+10;
int a[N];
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+2,a+n+1);
for(int i=2;i<=n;i++)
{
if(a[i]>a[1])
a[1]=(a[i]+a[1]+1)/2;
}
printf("%d\n",a[1]);
}
return 0;
}
C. Count Binary Strings
题目链接:Problem - C - Codeforces
样例输入:
3
1 0 2
1 0
1
样例输出:
6
题意:给定一个n,代表我们需要构造的01串的长度,接下来给定一个数组a[i][j],代表从第i个位置到第j个位置的限制。其中i<=j
如果a[i][j]=1,那么从第i个位置到第j个位置的字符都是相同的
如果a[i][j]=2,代表从第i个位置到第j个位置的字符中存在不同字符
如果a[i][j]=0,代表从第i个位置到第j个位置的字符不做限制
问满足这些限制的情况下我们能够构造出来的01串的方案数,答案对998244353取余。
分析:通过分析我们可以发现a[1][r],a[2][r],……,a[r][r]一定呈现2 2……2 1 1……1的特征,这是显然的,因为一开始a[r][r]肯定为1,如果第r-1个位置和第r个位置上的数相同,那么就有a[r-1][r]=1,否则就有a[r-1][r]=2,一旦某个i满足a[i][r]=2,那么所有的j<=i都有a[j][r]=2.
设f[i][j]表示a[1~i-1][j]等于2,a[i~j][j]等于1的合法方案数,那么答案就是.
我们直接遍历更新f[l][r],我们首先判断a[1~l-1][r]是不是全都为2或者0,以及a[l~r][r]是否全都为1,如果不满足这两个条件那么显然有f[l][r]=0.这个时候我们来分两种情况考虑,第一种情况就是第r+1个位置和第r个位置的字符相同,那么就有f[l][r+1]=f[l][r+1]+f[l][r],如果第r+1个位置和第r个位置的字符不同,那么就有f[r+1][r+1]=f[r+1][r+1]+f[l][r],因为第r个字符和第r+1个字符不同,所以一定有a[l~r][r+1]=2,所以直接加到f[r+1][r+1]上即可。
初始化条件:f[1][1]=2,代表第一个位置可以为0可以为1
细节见代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=103,mod=998244353;
int a[N][N];
int f[N][N];//f[i][j]表示a[1~i-1][j]等于2,a[i~j][j]等于1的合法方案数
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
cin>>a[i][j];
f[1][1]=2;
for(int r=1;r<=n;r++)
for(int l=1;l<=r;l++)
{
bool flag=true;
for(int i=1;i<l;i++)
if(a[i][r]==1) flag=false;
for(int i=l;i<=r;i++)
if(a[i][r]==2) flag=false;
if(!flag) f[l][r]=0;
f[l][r+1]=(f[l][r+1]+f[l][r])%mod;//第r+1个位置上的数等于第r个位置上的数
f[r+1][r+1]=(f[r+1][r+1]+f[l][r])%mod;//第r+1个位置上的数不等于第r个位置上的数,那么就有a[1~r][r+1]=2
}
int ans=0;
for(int i=1;i<=n;i++)
ans=(ans+f[i][n])%mod;
printf("%d\n",ans);
return 0;
}
D. Playoff
题目链接:Problem - D - Codeforces
样例输入:
3
101
样例i输出:
4 5 6 7
题意:给定 2^n名参赛选手,其能力值是 [1,2^n] 的排列。一共进行 n 轮比赛。每轮比赛和自己相近的选手进行比赛。最后在 n 轮游戏后,会有一个选手胜出。给定一个长度为n的01串代表规则,s[i]=0 表示在第i轮能力低的获胜,否则能力高的获胜。求能力值为多少的选手最终可能获胜。
分析:不难发现,满足题意的能力值一定是连续的。我们不妨分析一下能力值最小是多少,假设是x,假如n论比赛中有cnt1轮比赛的规则是能力高的获胜,那么在第cnt1轮能力大的选手获胜的比赛后所有小于x编号的选手都已经被淘汰,在第cnt1-1轮能力大的选手获胜的比赛后,还会剩下一个比x编号小的选手,同理为了使得这两名小编号选手晋级,那么在第cnt1-2轮能力大的选手获胜的比赛后应该剩下4名编号小于等于x的选手,其中两名选手是为了另外两名选手晋级用的,按照这个方法递推我们可以发现在第cnt1-i轮能力大的选手获胜的比赛后应该剩下2^i个编号小于等于x的选手,那么令i=cnt1可以得到x=2^cnt1,同理可以分析编号大的情况,由于方法是相同的,所以这里就不赘述了。
下面是代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=23;
char s[N];
int main()
{
int n;
cin>>n;
scanf("%s",s+1);
int cnt0=0;//记录0的个数
int cnt1=0;//记录1的个数
for(int i=1;i<=n;i++)
if(s[i]=='0') cnt0++;
else cnt1++;
int l=1<<cnt1;
int r=(1<<n)+1-(1<<cnt0);
for(int i=l;i<=r;i++)
printf("%d ",i);
return 0;
}