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;
}