题目地址:牛客周练15
A题:
目前我只知道两种方法,第一种,直接暴力,居然能过,代码如下(不做过多解释):
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10000+8;
int Ai[maxn];
int B[maxn];
int main()
{
int n;
scanf("%d",&n);
memset(Ai,0,sizeof(Ai));
memset(B,0,sizeof(B));
for(int i = 1; i <= n; i++)
{
scanf("%d",&Ai[i]);
}
for(int t = 1; t <= n; t++)
{
bool flag = false;
for(int j = t+1; j <= n; j++)
{
if(Ai[j] > Ai[t])
{
B[t] = j;
flag = true;
break;
}
}
if(!flag) B[t] = 0;
}
for(int cnt = 1; cnt <= n; cnt++)
{
if(cnt == 1) printf("%d",B[cnt]);
else printf(" %d",B[cnt]);
}
printf("\n");
return 0;
}
我们正常比赛的时候第一种方法我个人感觉可能过不了,那么试试第二种。
第二种方法就是构建一个线段树,树根是区间内最大的值,然后依次查找。
线段树解法:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+8;
int T,ans;
int a[maxn] = {0},B[maxn] = {0};
struct Tree
{
int l,r,val,id;
}Tree[maxn*4];
void build(int k,int ll,int rr)//id记录标号,val大小
{
Tree[k].l = ll,Tree[k].r = rr;
if(Tree[k].l == Tree[k].r)
{
int s = ll;
Tree[k].id = s;
Tree[k].val = a[s];
return;
}
int mid = (ll+rr)>>1;
build(k<<1,ll,mid);
build(k<<1|1,mid+1,rr);
if(Tree[k<<1].val > Tree[k<<1|1].val)
{
Tree[k].val = Tree[k<<1].val;
Tree[k].id = Tree[k<<1].id;
}
else
{
Tree[k].val = Tree[k<<1|1].val;
Tree[k].id = Tree[k<<1|1].id;
}
}
int query(int k,int ll,int rr,int res)//查找时在所有的可能值中找最小的
{
if(Tree[k].l == Tree[k].r&&Tree[k].l >= ll&&Tree[k].r <= rr&&Tree[k].val > res)
{
return Tree[k].id;
}
int mid = (Tree[k].l+Tree[k].r)>>1;
if(ll <= mid&&Tree[k<<1].val > res) ans = min(ans,query(k<<1,ll,rr,res));
if(rr >= mid+1&&Tree[k<<1|1].val > res) ans = min(ans,query(k<<1|1,ll,rr,res));
return ans;
}
int main()
{
scanf("%d",&T);
for(int i = 1; i <= T; i++)
{
scanf("%d",&a[i]);
}
build(1,1,T);
for(int i = T; i >= 1; i--)
{
ans = T+1;
int res = query(1,i+1,T,a[i]);
if(res > T) res = 0;
B[i-1] = res;
}
for(int t = 0; t < T; t++) printf("%d ",B[t]);
printf("\n");
return 0;
}
B题:
刚开始给我干懵了,树状数组? 所以我也没做出来,首先,对于每一个数,他们×的最小值应该是1吧,如果每个数都是正数,那么我从第一个数开始删除,最后的结果就是每一个数都乘一个1,但题里可能有负数,我们尽可能让负数乘大值,让剩下的正数从头开始一个一个删除,所以这题应该是贪心算法,先删负数(从后向前删,保持负数的下标最大),最后从前往后删正数,就等效于正数都乘1,负数都乘下标
代码:
//15-B
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int T;
scanf("%d",&T);
ll ans = 0;
ll x;
for(int i = 1; i <= T; i++)
{
scanf("%lld",&x);
ans += (x > 0)? x:x*i;
}
cout<<ans<<endl;
return 0;
}
C题:
其实到现在我也没完全明白C题,我估计题目表达的意思并不完整,或者就是我太菜了,但从被人的代码里我门能学到什么
大致思路:
因为要求字典序最小,所以我们肯定从1开始,把他赋为0,所有跟1相连的,肯定是2的x次幂(x >= 0&&x <= n-1),因为他只能有一个1,那么我们假设2这个点于1相连,那么与2相连的点(除了1),他的二进制表示里肯定多了一个1,所以这题我们用BFS,层数代表1的格式,1点为0层,和1相连的点为1层,但要满足所有的点都在(0-2^n-1),下一层的二进制就要由上一层二进制合并得到(仅仅我模拟得到的规律,不对就告诉我,对的话告诉我咋推出来的,感谢大佬,好人一生平安)
这里涉及到的二进制的用法可以看我学校的一个大佬写的:二进制
别人的码:
#include<bits/stdc++.h>
using namespace std;
int i,j,n,m,t,ans,x,y,r,f,DP[300005],Q[300005];
vector<int>R[300005];
bool V[300005],T[300005];
struct node
{
bool bit[300005];
}S[20];
bool cmp(node a,node b)
{
for(int i=1;i<=(1<<n);i++)if(a.bit[i]!=b.bit[i])
return a.bit[i]>b.bit[i];
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=(1<<n);i++)R[i].clear(),DP[i]=V[i]=T[i]=0;
while(m--)
{
scanf("%d%d",&i,&j);
R[i].push_back(j),R[j].push_back(i);
}
f=r=DP[1]=0,T[1]=V[1]=1;
for(i=0;i<R[1].size();i++) //先给第一层赋值
{
j=R[1][i];
DP[j]=(1<<i),T[j]=1,Q[r++]=j;
}
while(r!=f)//类BFS
{
x=Q[f++],V[x]=1;
for(i=0;i<R[x].size();i++)
{
j=R[x][i];
if(V[j]) continue;
DP[j]|=DP[x];//本层由上一层合并得到
if(!T[j])T[j]=1,Q[r++]=j;
}
}
for(i=1;i<=(1<<n);i++)//i代表第i个数
{
for(j=0;j<n;j++)//j代表第i个数的第j位
{
S[j].bit[i]=(DP[i]>>j)&1;//一位一位取出来,用结构体存储二进制
}
}
sort(S,S+n,cmp);//按字典序排序,画图看一下就懂了
for(i=1;i<=(1<<n);i++)
{
for(ans=j=0;j<n;j++) if(S[j].bit[i]) ans|=(1<<j);//按照结构体对二进制的记录还原
printf("%d ",ans);
}
cout<<endl;
}
return 0;
}
D题:
看到往一堆树里加什么东西就会自然联想到线段树:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+500;
const ll mod=23333;
int n,m,ans = 0;
ll a[N],b[N];
vector<int>G[N];
int L[N],R[N];
struct Tree
{
int l,r;
ll val,Val,tag;
} t[N*4];
int tim=0;
void dfs(int x,int y)//给x设置左右区间
{
L[x] = ++tim;
b[tim] = a[x];
for(int cnt = 0; cnt < G[x].size(); cnt++)
{
if(G[x][cnt] != y)
{
dfs(G[x][cnt],x);
}
}
R[x] = tim;
}
void update(int p)
{
t[p].val = (t[p<<1].val+t[p<<1|1].val)%mod;
t[p].Val = (t[p<<1].Val+t[p<<1|1].Val)%mod;
return;
}
void build(int p,int l,int r)
{
t[p].l = l,t[p].r = r;
if(l == r)
{
t[p].val = b[l];
t[p].Val = (long long)b[l]*b[l]%mod;
return ;
}
int mid = (l+r)>>1;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
update(p);
}
void down(int p)
{
if(t[p].tag)
{
t[p<<1].Val = ((t[p<<1].Val + (t[p<<1].r-t[p<<1].l+1)*t[p].tag*t[p].tag)%mod + 2*t[p<<1].val*t[p].tag%mod)%mod;
t[p<<1].val = (t[p<<1].val + (t[p<<1].r-t[p<<1].l+1)*t[p].tag)%mod;
t[p<<1].tag = (t[p<<1].tag + t[p].tag)%mod;
t[p<<1|1].Val = ((t[p<<1|1].Val + (t[p<<1|1].r-t[p<<1|1].l+1)*t[p].tag*t[p].tag)%mod + 2*t[p<<1|1].val*t[p].tag%mod)%mod;
t[p<<1|1].val = (t[p<<1|1].val + (t[p<<1|1].r-t[p<<1|1].l+1)*t[p].tag)%mod;
t[p<<1|1].tag = (t[p<<1|1].tag + t[p].tag)%mod;
t[p].tag = 0;
}
return;
}
void change(int p,int L,int R,ll x)
{
if(t[p].l >= L&&t[p].r <= R)
{
t[p].Val = ((t[p].Val + (t[p].r-t[p].l+1)*x*x)%mod + 2*t[p].val*x%mod)%mod;
t[p].val = (t[p].val + (t[p].r-t[p].l+1)*x)%mod;
t[p].tag = (t[p].tag + x)%mod;
return;
}
down(p);
int mid = (t[p].l+t[p].r)>>1;
if(L <= mid) change(p<<1,L,R,x);
if(R >= mid+1) change(p<<1|1,L,R,x);
update(p);
}
ll ask(int p,int L,int R)
{
if(t[p].l >= L&&t[p].r <= R)
{
return t[p].Val;
}
down(p);
ll ans = 0;
int mid = (t[p].l+t[p].r)>>1;
if(L <= mid) ans=(ans+ask(p*2,L,R))%mod;
if(R >= mid+1) ans=(ans+ask(p*2+1,L,R))%mod;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
int u,v;
for(int i = 1; i <= n-1; i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
build(1,1,n);
int tye,x,y;
while(m--)
{
scanf("%d",&tye);
if(tye == 1)
{
scanf("%d%d",&x,&y);
change(1,L[x],R[x],(long long)y);
}
else if(tye == 2)
{
scanf("%d",&x);
printf("%lld\n",ask(1,L[x],R[x])%mod);
}
}
return 0;
}