2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

现场只过了4题 险些没名额,1,6,7,8

其中7,8,我敲,1参与思考,6:zsben敲

太菜了,之前一直温水煮青蛙,今天发现差距了,中期题不会做,只会做思维水题。

补题情况:

---队友过的 且未补题

Ο 自己过的或赛后补题

题号1234567891011 
状态ΟΟ...---ΟΟ .. 

1001:水题,(a^c  )& ( b^c) 最小,

按位看

a:1 b:1  c这一位必须是1,才能让这一位变0.

a:1  ,b:0或a:0,  b:1或a:0  b:0这样c任取,那我们取C==0

就相当于a&b.但题目说C必须正整数。所以当c取0时  取1即可

代码略

1002:

一道很有思维度的简单线段树。

比赛的时候一直想主席树套树状数组转在线,又想并查集,越想越复杂。

其实仔细思考可以发现,l始终是1,只有r发生变化。

询问的是第一个权值大于k,且不在1-->r 之间的数。

我们看到数据范围,1<=n,a[i],k<=1e5,而加的数是1e6,

把一个数加上1e6相当于在权值线段树里把他删去。自然而然的想到建一棵权值线段树。

比赛的时候想到了这里,然后怎么询问第一个权值大于k,且不在1-->r之间的数不会弄。

其实我们权值线段树稍微变一下,每个结点维护这个数出现的位置。

还是按权值去建树。

比如样例:

4 3 1 2 5   -->3 4 2 1 5.

数字’1‘的位置是3,所以l==r==1时,st[o]存的是。

这样一变化,问题就转化成了:求整体区间内:第一个位置大于r且权值大于等于k的数。  

这样就变成了一个很基础的权值线段树的处理了。

找到第一个位置后,直接返回,这样的复杂度是找第一个位置的复杂度:也就是logn。

 

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M= 1e5+7;
int st[M<<2],pos[M],a[M],qz[M];
int n,m,sz=100000+7,now;
bool f;
#define ls o*2
#define rs o*2+1
void bd(int o,int l,int r)
{
	if(l==r)
	{
		st[o]=pos[l];
		return ;
	}
	int m=(l+r)/2;
	bd(ls,l,m);
	bd(rs,m+1,r);
	st[o]=max(st[ls],st[rs]);
}
void up(int o,int l,int r,int x)
{
	if(l==r)
	{
		st[o]=sz;
		pos[l]=sz;
		return ;
	}
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x);
	else up(rs,m+1,r,x);
	st[o]=max(st[ls],st[rs]);
}
void qu(int o,int l,int r,int y,int k)
{
	//printf("%d  %d   %d   y:%d  k:%d    st[ls]: %d   st[rs]:%d\n",l,r,st[o],y,k,st[ls],st[rs]);
	if(f||r<k)return ;
	//if(l<k)return ;
	if(l==r)
	{
		now=l;
		f=true;
		return ;
	}
	int m=(l+r)/2;
	if(st[ls]>y) qu(ls,l,m,y,k);
	if(st[rs]>y) qu(rs,m+1,r,y,k);
}
int main()
{
	int t,las=0;
	cin>>t;
	while(t--)
	{
		las=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<M*2;i++)pos[i]=sz;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			pos[a[i]]=i;
			qz[i]=a[i];
		}
		bd(1,1,sz);
		for(int i=1;i<=m;i++)
		{
			int c,y,k;
			scanf("%d",&c);
			if(c==1)
			{
				scanf("%d",&y);
				y=y^las;
			//	printf("----%d\n",qz[y])
				up(1,1,sz,qz[y]);
			}
			else
			{
				scanf("%d%d",&y,&k);
				y=y^las;k=k^las;
				f=false;
				qu(1,1,sz,y,k);
				printf("%d\n",now);
				las=now;
			}
		}
	}
   	return 0;
}

/*
3
5 9
4 3 1 2 5 
2 1 1
2 3 3
2 3 2
2 3 1
2 4 1
2 5 1
*/

1006,倒着想即可。

1007,模拟

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M= 1e5+7;
int a[M];
char s[1100][1100];
int main()
{
    int t;
    s[1][1]='C';
    s[1][2]='C';
    s[2][1]='P';
    s[2][2]='C';
    for(int l=1;l<=9;l++)
    {
        int now=1<<(l+1);
        int pre=now/2;
        for(int i=1;i<=pre;i++)
            for(int j=pre+1;j<=now;j++)
            {
                s[i][j]=s[i][j-pre];
                s[i+pre][j]=s[i][j-pre];
                if(s[i][j-pre]=='C')
                    s[i+pre][j-pre]='P';
                else
                    s[i+pre][j-pre]='C';
            }
    }
    cin>>t;
    while(t--)
    {
        int d;
        scanf("%d",&d);
        int w=1<<d;
        for(int i=1;i<=w;i++)
        for(int j=1;j<=w;j++)
        {
            printf("%c",s[i][j]);
            if(j==w)puts("");
        }
    }
     
       return 0;
}


1008,

我搞完1007后,zsben1006过了,然后先过了1006,去想1002自闭。。看1008过的人多了,就看了下,

直接就有思路了:首先,

最少的时间肯定时先抓一条鱼,然后加上炖鱼的时间,在炖鱼的时间取抓鱼。

但是会有去抓鱼但炖鱼好了的情况。

我们让这种浪费的时间最少即可。

先让所有炖鱼的时间%k,然后从大到小排序(其实没必要优先队列),这样肯定是抓鱼时间浪费最少的排序,抓满n条即可。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
#define F first
#define S second
const ll INF64=8000000000000000000LL;
const int INF=0x3f3f3f3f;
const ld PI=acos(-1);
const ld eps=1e-9;
const ll MOD=ll(1e9+7);
const int M = 1e5 + 10;
void modup(int&x){if(x>=MOD)x-=MOD;}
ll a[M];

priority_queue<ll> q;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll n,k;
        scanf("%lld%lld",&n,&k);
        ll w=0;
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            ans+=a[i];
            w+=a[i]/k;
            ll zz=a[i]%k;
            q.push(zz);
        }
//        puts("ok");
        ans+=k;
        while(w<n-1)
        {
            ll now=q.top();
            q.pop();
            ans+=k-now;
            w++;
        }
        printf("%lld\n",ans);
        while(!q.empty())
        {
            q.pop();
        }
    }    
       return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值