Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2) A-E

A:

0: a 

1:b

2:a^b

3:a^b^b=a;

4:a^a^b=b;  

#include<bits/sdtc++.h>
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 ll MOD=ll(1e9+7);
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
const int M = 1e5 + 10;
int main()
{
	int t;
    cin>>t;
    while(t--)
    {
    	int a,b,n;
    	scanf("%d%d%d",&a,&b,&n);
    	int c=a^b;
    	n%=3;
    	if(n==0)
    	printf("%d\n",a);
    	else if(n==1)printf("%d\n",b);
    	else printf("%d\n",c);
	}
    return 0;
}

B:二分删除长度。

离散化后n^2check  复杂度n^2logn

还有个n^2的做法: 枚举删除区间的左端点,右端点从n往左开始枚举加入数,直到重复数了,这个点右边的点就是右端点。

#include <bits/stdc++.h>
using namespace std;
const int M = 2e3 + 10;
int a[M],n;
int li[M];
int mp[M];
bool ck(int x)
{
	for(int i=1;i+x-1<=n;i++)
	{
		for(int k=1;k<M;k++)
		mp[k]=0;
		bool f=true;
		for(int j=1;j<=n;j++)
		{
			if(i<=j&&j<=i+x-1)
			continue;
			if(mp[a[j]]>0)
			{
			//	printf("----%d  %d  %d\n",i,j,mp[a[j]]);
				f=false;
				break;
			}
			mp[a[j]]++;
		}
		if(f)
		{
	//		printf("++++++  %d\n",i);
			return true;
		}
	}
	return false;
}
int main()
{
    cin>>n;
    int sz=0;
    for(int i=1;i<=n;i++)
    {
    	scanf("%d",&a[i]);
    	li[++sz]=a[i];
	}
	sort(li+1,li+1+sz);
	sz=unique(li+1,li+1+sz)-li;
	for(int i=1;i<=n;i++)
	{
		a[i]=lower_bound(li+1,li+1+sz,a[i])-li;
	}
/*	for(int i=1;i<=n;i++)
	printf("%d\n",a[i]);*/
	int l=0,r=n,pos;
	while(l<=r)
	{
		int m=(l+r)/2;
	//	printf("%d  %d  %d\n",l,r,m);
		if(ck(m))
		{
			pos=m;
			r=m-1;
		}
		else
		{
			l=m+1;
		}
	}
	printf("%d\n",pos);
    return 0;
}
 

C:

发现按位异或,所有数每位刚好一半1,一半0。因为一半1,一半0异或刚好等于0.所以我们一定能构造出行列异或等于0的矩阵。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M= 1e3+7;
int a[M][M];
int main()
{
	/*
	ios::sync_with_stdio(false);
  	cin.tie(0);*/
  	int n;
	scanf("%d",&n);
    int l=0,r=1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
    	if(i<=n/2)
    	{
    		a[i][j]=l;
    		l+=2;
		}
		else
		{
			a[i][j]=r;
			r+=2;
		}
	}
/*	for(int i=1;i<=n;i++)
	{
		int ans=0;
		for(int j=1;j<=n;j++)
		ans^=a[j][i];
		printf("%d\n",ans);
	}*/
    
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
		if(j==n)
		{
			printf("%d\n",a[i][j]);
			continue;
		}
    	printf("%d ",a[i][j]);
	}
    return 0;
}
 

D:观察出:最小的数一定是最右边的0,即:前面所有数都比他大。

然后去掉这个数后,后面的数肯定要减去1,因为后面的数都比他大。

然后再找到最右边的0,一定是次小的的数即2.然后去掉这个数,后面的数肯定要减去2 .

重复上述操作即可,暴力复杂度n^2,

查询最小的数且最右边的数的坐标和区间更新,线段树维护下,复杂度 nlogn

注意,删除这个数相当于把这个数加一个很大的数,这样最小值就不会找到它。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M= 2e5+7;
const ll INF64=80000000000000000ll;
#define ls o*2
#define rs o*2+1
ll st[M<<2],tag[M<<2];
ll a[M],p[M<<2];
void pd(int o,int l,int r)
{
	if(tag[o]==0)
	return ;
	int m=(l+r)/2;
	tag[ls]+=tag[o];
	tag[rs]+=tag[o];
	st[ls]+=tag[o];
	st[rs]+=tag[o];
	tag[o]=0;
}
void pu(int o) 
{
    if (st[ls]<st[rs])
        st[o]=st[ls],p[o]=p[ls];//最小值的位置 
    else
        st[o]=st[rs],p[o]=p[rs];
}
void bd(int o,int l,int r)
{
//	puts("ok");
	tag[o]=0;
	if(l==r)
	{
		st[o]=a[l],p[o]=l;
		return;
	}
	int m=(l+r)/2;
	bd(ls,l,m);
	bd(rs,m+1,r);
	pu(o);
}
void up(int o,int l,int r,int x,int y,ll d)
{
	if(x>y)return ;
	if(x<=l&&r<=y)
	{
		st[o]+=d;
		tag[o]+=d;
		return ;
	}
	pd(o,l,r);
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x,y,d);
	if(y>m)up(rs,m+1,r,x,y,d);
	pu(o);
}
ll b[M];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	bd(1,1,n);
	for(int i=1;i<=n;i++)
	{
		b[p[1]]=i;
		int pos=p[1];
		up(1,1,n,pos+1,n,-i);
		up(1,1,n,pos,pos,1000000000000000000);
	}
	for (int i=1;i<n;i++)
        printf("%lld ",b[i]);
    printf("%lld\n",b[n]);
	return 0;
}

E:复杂度nlogn^2

应该属于势能线段树,复杂度分析比较复杂,应该是这个。

 

/*枚举1e6序列所有数, 
线段树维护每列的和,和当前行的贡献 
每个数跟区间内数比大小,一行数算完后更新这一行的答案/
区间最小值大于最大值就不往下更新。更新区间最大值	
单点查询 
*/ 
//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
//unordered_map<int,int>mp;
const int M= 1e6+7;
const int INF = 1e9+7;
ll st[M<<2],mn[M<<2],mx[M<<2],tag[M<<2];
ll vis[M<<2];
#define ls o*2
#define rs o*2+1
#define m (l+r)/2
void bd(int o,int l,int r)
{
	if(vis[o]==0)return;
	vis[o]=0;
	mx[o]=mn[o]=tag[o]=-INF;
	if(l==r)return ;
	bd(ls,l,m);bd(rs,m+1,r);
}
void pd(int o)
{
	if(tag[o]==-INF)return;
	tag[ls]=max(tag[o],tag[ls]);
	tag[rs]=max(tag[o],tag[rs]);
	mx[ls]=max(mx[ls],tag[o]);
	mx[rs]=max(mx[rs],tag[o]);
	mn[ls]=max(mn[ls],tag[o]);
	mn[rs]=max(mn[rs],tag[o]);
	vis[ls]=1,vis[rs]=1;
	tag[o]=-INF;
}
void pu(int o)
{
	mx[o]=max(mx[ls],mx[rs]);
	mn[o]=min(mn[ls],mn[rs]);
}
void up(int o,int l,int r,int x,int y,ll d)
{
	if(mn[o]>=d)return;//没必要更新了 
//	printf("%d   %d\n",l,r);
	vis[o]=1;
	if(x<=l&&r<=y)
	{
		mn[o]=max(mn[o],d);
        tag[o]=max(tag[o],d);
        mx[o]=max(mx[o],d);
        return ;
	}
	pd(o);
	if(x<=m)up(ls,l,m,x,y,d);
	if(y>m)up(rs,m+1,r,x,y,d);
	pu(o);
}
void gao(int o,int l,int r)
{
//	printf("%d   %d  mx   %d   mn  %d   st  %d\n",l,r,mx[o],mn[o],st[o]);
	if(mx[o]==mn[o])
	{
		st[o]+=mx[o];
/*区间中,每个数的值都为st[o]. 
这里每行,每个小区间肯定只会加一次,只加这一行的贡献。由
于数很大所以要这样快速处理,这样就只跟更新次数有关而非区间长度 
*/ 
		return ;
	}
	pd(o);
	gao(ls,l,m);
	gao(rs,m+1,r);
}
ll qu(int o, int l, int r, int k) {
//	printf("---   %d  %d  %d\n",l,r,st[o]);
    if (l == r)
        return st[o];
    ll ans = st[o];
    if (k <= m)
        ans += qu(ls, l, m, k);
    else
        ans += qu(rs, m + 1, r, k);
    return ans;
}
int main()
{
	int q,n;
	cin>>q>>n;
	for(int i=1;i<=q;i++)
	{
		int l,x;
		bd(1,1,n);
		scanf("%d",&l);
		for(int j=1;j<=l;j++)
		{
			scanf("%d",&x);
			//j,n-l+j
			up(1,1,n,j,n-l+j,x);
		}
		if(l<n)
		{
			up(1,1,n,1,n-l,0);
			up(1,1,n,l+1,n,0);
		}
		gao(1,1,n);
	}
	for(int i=1;i<=n;i++)
			printf("%lld ",qu(1,1,n,i));
   	return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值