2022ccpc威海站复现+补题

A. Dunai

题意:

每组成一个队伍需要五个人,给定n个冠军队伍以及队员名字(有可能重复),给定m个队员名以及每个队员的位置(保证每个队员不重复),将这些队员组成队伍去参加比赛,每个队伍都至少有一个冠军队员,问最多可以组成多少个队伍。

题目特地强调每个冠军队员的位置不会改变,我们误以为是只有冠军队员位置不变,其他队员位置可以随意更换,后面才知道是每个队员的位置都不会改变。。。。。。

下次读题一定要更认真仔细,以及发现是签到但怎么也写不对的时候一定要反复斟酌题意。。。怀疑自己读错了马上重读,不要犹豫。

思路:

由于每个队伍都至少需要一名冠军队员,因此组成的队伍数最多为冠军队员总数;

由于每5个人组一队,组成的队伍数最多为m/5;

由于每个队员的位置不能改变,因此分别记录每个位置的冠军队员以及非冠军队员,组成的队伍数不超过这5个位置上最少的位置的总人数;

因此取这三个数最小即为答案。

代码:

#include
#define ll long long
using namespace std;
int n,m,t;
int sum;
int cnt[10]={0},cnt1[10]={0};
char sa[40];
mapp;
 int main()
 {
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=5;j++)
        {
            scanf("%s",sa);
            p[sa]=1;
        }
    }
    cin>>m;
    int mini=m/5;
    sum=0;
    int putong=0;//普通人数
    for(int i=1;i<=m;i++)
    {
        scanf("%s",sa);
        scanf("%d",&t);
        if(p[sa]==1) cnt[t]++;
        else 
		{
			cnt1[t]++;
			putong++;
		}
    }
    sum=m-putong;//当前冠军队员人数
 
      mini=m/5;
      for(int i=1;i<=5;i++)
      {
      	mini=min(mini,cnt[i]+cnt1[i]);
	  }
 
    cout<

C. Grass

题意:

给定n个点的坐标,找出任意五点满足以其中一点为中心点连接另外四个点的线段不相交,不重合,如下图。

2022ccpc威海站复现+补题_第1张图片

思路:

要保证四条线段不重合,不相交,首先这五个点不能共线,所以先暴力找出不共线的五个点,就算其中四点共线,只要找到正确的中心点连接这四个点也可以满足条件,如下图。

2022ccpc威海站复现+补题_第2张图片

找到不共线的五个点之后,枚举每个点作为中心点的情况;当这个点作为中心点连接另外四个点的线段上不存在任意一点,即满足条件;所以还需要枚举判断每个线段和其他点的关系。

复杂度是o(5*5*5*n).

判断五点是否共线,依次判断前两个点和第三个点、第四个点、第五个点是否三点共线,只要有一组满足不是三点共线,则这五个点不满足五点共线。因此写一个函数判断三点共线。

判断某点是否作为中心点符合条件,需要判断连接的四个线段是否存在其他点,因此写一个函数判断点C是否在线段AB上。

代码:

#include
#define ll long long
#define double long double
using namespace std;
const int maxn=1e5+10;
const double eps=1e-10;
struct point
{
  int x,y;
};
point s[maxn];
bool check_abc(point a,point b,point c)//判断三点是否共线,不共线返回true,共线false
{
  if((a.y-b.y)*(a.x-c.x)==(a.y-c.y)*(a.x-b.x))return false;
  return true;
}
bool check_ab(point a,point b,point c)//判断c是否在ab线段上
{
  if(!check_abc(a,b,c))//三点共线,判断c是否在ab中间
  {
    if((c.x>a.x&&c.xb.x&&c.xa.y&&c.yb.y&&c.y>n;
  for(int i=0;i>s[i].x>>s[i].y;
  if(n<5){cout<<"NO"<>t;
  while(t--)solve();
  //system("pause");
  return 0;
}

E. Python Will be Faster than C++

代码:

#include
#define ll long long
using namespace std;
#define N 20
int n,k;
ll a[N];
 
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int fl=0,j=1,x=a[n]-a[n-1];
    if(x>=0)
    {
        for(j=1;;j++)
        {
            if(x*j

G. Grade 2

题意:

对于x,以及每个区间[l,r]输出下列式子的答案。

2022ccpc威海站复现+补题_第3张图片

 

思路:

这是一题打表找规律题,通过打表我们发现对于每个x,遍历k,求该式子

,会发现该式子的答案会不停的循环,因此可以猜测,对于每个x,都有循环节,对x=[1,20]打表找规律,我们发现每个等于2^n的数,循环节为1,且答案为x本身,对于小于2^n的数,它的循环节总数2^n或者2^n的因数。

因此我们可以对每个x先求一个循环节的长度,当作是大于等于它的第一个2^n,等于2^n的数,循环节为1答案,并记录该循环节1的个数前缀和。

对于每个区间,答案为sum[r]-sum[l-1]。

代码:

#include
#define ll long long
#define mod 998244353
const int maxn=1e6+10;
using namespace std;
ll sum;
int x,n;
struct p
{
	ll l,r;
}a[maxn];
ll c;//循环节长度
int jc[2*maxn];
int sum1[2*maxn];//前缀和
ll gcd(ll a, ll b)
{
    return a == 0 ? b : gcd(b % a, a);
}
ll sum_x(ll x)
{
	ll res=0;
	res=(x/c)*sum1[c]+sum1[x%c];
	return res;
}
int main()
{
    scanf("%d%d",&x,&n);
    for(ll i=1;i<=n;i++){scanf("%lld%lld",&a[i].l,&a[i].r);}
		double t=log2(x);int t1=(int)t;
		if(x==1||pow(2,t1)==x)c=1;
		else c=pow(2,t1+1);
		sum1[0]=0;sum=0;
		for(ll i=1;i<=c;i++)
		{
			if(gcd((i*x)^x,x)==1)
			{
				jc[i]=1;
				sum++;
			}
			else jc[i]=0;
			sum1[i]=sum;
		}
		//for(int i=1;i<=50;i++)cout<

J. Eat, Sleep, Repeat

题意:

给定n堆数以及k个限制。FuuFuu和Pico轮流对某个堆进行-1操作,当某个人不能操作了就输了。

限制lim[i]=x表示在操作过程中(任意时刻)出现i这个数的的数量不能超过x个。

思路:

由于最终态是确定的,因此我们只需要知道到达最终态需要进行几次操作,若是奇数,FuuFuu赢,否则Pico赢。

若没有限制出现,则进行的操作数是总和;

否则,因此有限制,对于每个限制lim[i]=0,说明在操作过程中不能出现i这个数,因此大于i的数不能越过该数,我们可以进行分块操作,在每个间隔之间的区间让每个数减到最小且不超过每个数的限制。

代码:

#include 
#define ll long long
const int maxn = 1e5 + 100;
using namespace std;
ll a[maxn];
ll sum, res;
void solve()
{
  ll n, k;
  scanf("%lld%lld",&n,&k);
  sum = 0, res = 0;
  map l;
  map ex;
  vector zero;
  //memset(a, 0, sizeof(a));
  for (ll i = 1; i <= n; i++){scanf("%lld", &a[i]);l[a[i]]++;}   
  for (ll i = 1; i <= k; i++)
  {
    ll x,y;
    scanf("%lld%lld", &x, &y);
    l[x] = y;
    ex[x] = 1;
    if(y==0)zero.push_back(x);
  }
  int temp=1;
  if(zero.size()>0)zero.push_back(1e9 + 7);
  else temp=0;
  ll len=zero.size();
  sort(a + 1, a + 1 + n);	
  sort(zero.begin(),zero.end());
  ll j = 0, pos = -1; // j记录lim的数,pos记录lim=0的位置
  for (ll i = 1; i <= n; i++)
  {
    if(temp)
    {
      while ((pos

你可能感兴趣的:(ccpc,算法,c++,开发语言)