2021牛客多校第六场
题目链接
A Contracting Convex Hull
C Delete Edges
思路
就是要让三个点相加对n取模为0,找出所有满足的点,输出即可。证明略。
附上代码
#include <iostream>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 1000
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef double type;
int a[20000000][3];//数组开的一定要大一点,小了存不了,或者可以用vector
int main()
{
int n;
scanf("%d",&n);
int kx=0;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int k=(n-i-j)%n;//保证(i+j+k)%n==0
if(k<=0)k+=n;
if(k<=j)continue;
a[kx][0]=i;
a[kx][1]=j;
a[kx][2]=k;
kx++;
}
}
printf("%d\n",kx);
for(int i=0;i<kx;i++)
{
printf("%d %d %d\n",a[i][0],a[i][1],a[i][2]);
}
return 0;
}
F Hamburger Steak
思路
首先我们需要保证所有锅的时间和大于等于所有汉堡排的时间和,以及耗时最长的汉堡排不会再同一时刻分到两个锅中。𝑇=max{max a[i],(∑a[i])/𝑚)}。
然后在知道T的情况下,贪心地将每个锅的时间依次分配给每个汉堡排,当前这个锅没煎完的由下个锅煎完即可。
附上代码
#include <iostream>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 1000
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef double type;
ll a[100009];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
ll k=0,maxn=0,sum=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
maxn=max(maxn,a[i]);
sum+=a[i];
}
k=sum/m;
if(sum%m!=0)
k++;
maxn=max(maxn,k);//maxn表示每个盘子可以使用的最长的时间
ll nw=1;//表示盘子是第几个
long long lef=maxn;//表示每个盘子剩余的时间
for (int i=1; i<=n; i++)
{
if (lef>=a[i])//当前盘子可以煎完这个汉堡
{
printf("1 %lld %lld %lld\n",nw,maxn-lef,maxn-lef+a[i]);//第几个盘子,煎汉堡初始时间,煎汉堡结束时间
lef-=a[i];//更新盘子剩余时间
if (!lef)//盘子剩余时间为零时,更新至下一个盘子
{
lef=maxn;
nw++;
}
}
else//当前盘子无法煎完这个汉堡,先用下一个盘子的前几分钟煎,再用当前盘子的后几分钟煎,然后更新到下一个盘子
{
printf("2 %lld 0 %lld %lld %lld %lld\n",nw+1,a[i]-lef,nw,maxn-lef,maxn);//下一盘子数,0,煎完的时间,当前盘子数,初始时间,结束时间
nw++;//更新到新的盘子,并更新其剩余时间
lef=maxn-(a[i]-lef);
}
}
return 0;
}
H Hopping Rabbit
I Intervals on the Ring
思路
这道题题意就是给了你一些区间,先求出这些区间的并集,让你构造一些区间,使得你构造区间的交集等于题目中给出区间的并集。需要注意的就是给出的序列是一个环状序列,就是n和1是相连的,比如序列长度为10,区间为[8,2],意思就是8,9,10,1,2。
我们可以先将选中的元素标记出来,看看有几个连续的区间,需要注意的是当n和1都取到的时候,需要将第一个和最后一个区间合并。
附上代码
#include<iostream>
#include <bits/stdc++.h>
using namespace std;
int a[1005];//标记并集中是否包括某个元素
int k[1005];//存储连续被标记的区间,从0开始,两个数表示一个区间
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int l,r;
memset(a,0,sizeof(a));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
if(l<=r)//开始标记
for(int j=l;j<=r;j++)
{
a[j]=1;
}
else
{
for(int j=1;j<=r;j++)
{
a[j]=1;
}
for(int j=l;j<=n;j++)
{
a[j]=1;
}
}
}
int num=0;//表示区间的数量
int i;//表示a数组的下标,只需要遍历一遍即可
int kx=0;//表示k数组的下标
for(i=1;i<=n;)//求得连续区间,并将区间信息存在k数组中
{
if(a[i]==0)
{
i++;
continue;
}
bool bol=true;
while(1)
{
if(bol)
{
bol=false;
k[kx]=i;
kx++;
}
i++;
if(a[i]==0)
{
k[kx]=i-1;
kx++;
num++;
break;
}
}
}
bool biao=true;//如果最后一个和第一个都在并集中,那么就将两者合并为一个区间
if(a[1]==1&&a[n]==1&&num>1)
{
num--;
biao=false;
}
if(num>2)//这里我分为了三种情况,其实分两种情况就行
{
if(biao)
{
printf("%d\n",kx/2);
for(int kk=0;kk<kx-1;kk+=2)
{
printf("%d %d\n",k[kk],k[(kx-1+kk)%kx]);
}
}
else
{
kx-=2;
printf("%d\n",kx/2);
printf("%d %d\n",k[kx],k[kx-1]);
for(int kk=2;kk<kx-1;kk+=2)
{
printf("%d %d\n",k[kk],k[(kx-1+kk)%kx]);
}
}
}
else if(num==2)
{
if(biao)
{
printf("2\n%d %d\n%d %d\n",k[2],k[1],k[0],k[3]);
}
else
{
printf("2\n%d %d\n%d %d\n",k[2],k[1],k[4],k[3]);
}
}
else if(num==1)
{
if(biao)
{
printf("1\n%d %d\n",k[0],k[1]);
}
else
{
printf("1\n%d %d\n",k[2],k[1]);
}
}
else//我分析了一下,因为m不为0,因此这种情况应该不会出现,不过还是写上比较好
{
printf("-1\n");
}
}
return 0;
}