2018年东北农业大学春季校赛(周赛训练)
题解报告
题解顺序不是原来比赛的题目顺序
题目意思可以去原题了解
基本的一些理解和问题都在注释中
题目一:wyh的矩阵
//思维题,找规律,考虑中点的性质。
#include <cstdio>
#include <algorithm>
#include <iostream>
#define ll long long
using namespace std;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
ll N;cin>>N;
ll res=(N*N*(N*N+1))/2;
int temp=1,flag=1;
for(int i=0;i<N;i++)
{
res-=((N+1)/2+N*i)*(N-temp);
if(temp==N)flag=-1;//这里是一个取反的作用,主要是对称的来的
//有对称的都可以考虑下,简化代码。
temp+=flag*2;
}
cout<<res<<endl;
}
return 0;
}
题目二:wyh的迷宫
//基础的dfs\bfs也行
//bfs是用来找最短路径的,是全部蔓延的。
//dfs也能用来找最短路径,但是它是一条一条试的,比较慢,bfs容易先碰到。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=1000;
string mp[maxn];
int vis[maxn][maxn];//这里不是要找路径,只要能到达就可以了。就是找联通块。
//要回溯的是要抉择路径的,这里不需要。要(蔓延过去)
int dirx[4]={0,0,1,-1};
int diry[4]={1,-1,0,0};
int N,M;//搜索要用到,所以写在外面。
bool res=false;//判断是否有找到终点的。
void dfs(int x,int y)
{
if(res)return;
for(int i=0;i<4;i++)
{
int fx=x+dirx[i];
int fy=y+diry[i];
if(fx>=0&&fx<N&&fy>=0&&fy<M&&!vis[fx][fy]&&mp[fx][fy]!='x')
{
if(mp[fx][fy]=='t')
{
res=true;
return;
}
vis[fx][fy]=1;
dfs(fx,fy);
//不用vis[fx][fy]=0;//这个是用来找较为优秀的路径的。
//一个点走多个方向试试那条路比较短的。
}
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
memset(vis,0,sizeof(vis));
res=false;
cin>>N>>M;
for(int i=0;i<N;i++)cin>>mp[i];
int X,Y;//记录起始坐标的位置。
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
if(mp[i][j]=='s')
{
X=i,Y=j;
break;
}
vis[X][Y]=1;
dfs(X,Y);
if(res)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
题目三:wyh的阶乘
//考验对阶乘的理解程度,这道题明确说要求0有几个
//任何的一个数都可以转化为多个质数的乘积,这里基本每个数都可以拆出5和2
//在阶乘中只有最原始的2*5(质数相乘)才会多一个0,所以要看2和5的个数
//而一个数能被2除的概率要远远大于5,所以2的个数是一定够的
//所以要看5的个数,而阶乘中有个比较容易忘记的知识点就是:
//你要看一个阶乘总共有多少个指定的质数的乘积,那么只要
// while(N)
// {
// ans+=N/(质数);
// N/=(质数)
// }
//原理:从1,2,3...,N相乘,那么“N/(质数)”就可以得到是(一个质数)倍数的数的个数。
//N再次除以(质数)就可以得到是(质数的平方)的倍速的数的个数。
//这里如果是(质数的平方)的倍速的数一定也是(一个质数)的倍速,
//这里加了第二遍就刚好可以记录两个质数个数,所以刚刚好。
//N一直除以(质数)就可以以此类推
//这样就可以把所有的质数都给加回来
#include <cstdio>
#include <iostream>
using namespace std;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
int N;cin>>N;
int res=0;
while(N)
{
res+=N/5;
N/=5;
}
cout<<res<<endl;
}
return 0;
}
题目四:wyh的集合
//初中数学,尽量两边平分得到的组合才是最多的。
#include <cstdio>
#include <iostream>
using namespace std;
int main(void)
{
int T;cin>>T;
while(T--)
{
long long N;//这里要注意以下题目的大小
cin>>N;
if(N&1)cout<<(N/2)*((N+1)/2)<<endl;
else cout<<(N/2)*(N/2)<<endl;
}
return 0;
}
题目五:wyh的吃鸡
//由于是找最短路,所以使用bfs,用dfs可能会爆,可能会一直找不到,用bfs每次找最短时间的路就可以找到。
//因为这里每个状态的时间并不是都是由边决定的,所以要加入时间用优先队列来判断。
//dfs找最短要枚举所有的情况,一个点多次访问有好处的时候用,一个点的权重的时候用dfs。
//bfs和dfs的定义和用法仍需增强
//bfs加优先队列
//注意题目中的X为一块联通块。
//一个点分两种情况,人走的时候,车开的时候
//状态的记录分两种,一种可以记录你是不是做车过去的,一种是记录你这里有没有车。
//bfs需要大量的空间,边比较多的时候不推荐用。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
struct node
{
int x,y,c;//c为是否做上车;
ll time;//时间//到这个点所花费的时间,
//原因:需要记录实际的时间,权重不再是深度。
node(int X,int Y,int C,ll T)//参数有点多,最后自定义一个构造函数。
{
x=X;y=Y;c=C;time=T;
}
bool operator<(const node &other)const//优先队列排序用。
{
return time>other.time;
}
};
const int maxn=150;
int vis[maxn][maxn][2];//最后一维是分情况的,0为走,1为开车。
char mp[maxn][maxn];
int dirx[4]={0,0,-1,1};
int diry[4]={1,-1,0,0};
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
memset(vis,0,sizeof(vis));
int N,K;cin>>N>>K;
int X,Y=0;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
cin>>mp[i][j];
if(mp[i][j]=='S')X=i,Y=j;
}
priority_queue<node> q;
q.push(node(X,Y,0,0));//从这里扩散
int flag=0;
while(!q.empty())
{
node now=q.top();q.pop();
if(vis[now.x][now.y][now.c])continue;
vis[now.x][now.y][now.c]=1;
if(mp[now.x][now.y]=='X')
{
flag=1;//注意题目可能是搜索不到的,这里用个标记,看看有没有找到。
if(now.time>K)cout<<"NO"<<endl;
else{
cout<<"YES"<<endl;
cout<<now.time<<endl;
}
break;
}
for(int i=0;i<4;i++)
{
int fx=now.x+dirx[i];
int fy=now.y+diry[i];
//优先想到的写法。
//方法一:
if(fx>=0&&fx<N&&fy>=0&&fy<N&&mp[fx][fy]!='O')//注意这里的判断不能由!vis[fx][fy][now.c],这个now.c是上上个转移过去上个的状态
{ //这里不能直接拿来判断,这里卡了好久,哎~~。
if(mp[now.x][now.y]=='C'||now.c==1){//上个状态转移到这里的时候有车,所以快
if(now.time+1<=K||!vis[fx][fy][1])
q.push(node(fx,fy,1,now.time+1));
}else{//上个状态转移到这里的时候没有车,所以比较慢
if(now.time+2<=K||!vis[fx][fy][0])
q.push(node(fx,fy,0,now.time+2));
}
}
//方法二:
// if(fx>=0&&fx<N&&fy>=0&&fy<N&&mp[fx][fy]!='O')
// {
// int Car=mp[fx][fy]=='C'||now.c;//现在有没有车。
// if(!vis[fx][fy][Car])//记录的是现在有没有车的状态。
// {
// q.push(node(fx,fy,Car,now.time+2-now.c));//加的时间都是一样的
// }
// }
}
}
if(!flag)cout<<"NO"<<endl;
}
return 0;
}
题目六:wyh的物品
//二分,没想出来,虽然知道是O(nlogn),哎~~;
//这里的check是要用最终的结果,然后去反推每一个重量需要的价值
//然后用原始的价值去减它,看看是否能做出贡献,如果能为最后的值做出贡献,那么就一定是好的
//然后排序,选出K个较好的,看看是否都能做出贡献,因为总会有一个答案是最好的,而且是存在的
//因为如果K个较好的做出的贡献的总和为正数,那么他们就还可以继续为更高的比值做出贡献,所以比值还可以增大
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=1e6+10;
double v[maxn];
double w[maxn];
double temp[maxn];
int N,K;
bool check(double mid)
{
for(int i=0;i<N;i++)
temp[i]=v[i]-mid*w[i];//做出的贡献和应该做出的贡献的差值。
double res=0;
sort(temp,temp+N,greater());
//这里选出那些能做出贡献的人。
for(int i=0;i<K;i++)
res+=temp[i];//看看总体贡献是不是超出了,超出了预计的,那么比值就还可以增加,
//它们还能做出贡献。
return res>=0;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
cin>>N>>K;
for(int i=0;i<N;i++)cin>>w[i]>>v[i];
double l=0,r=1000000;
while(abs(r-l)>1e-8)
{
double mid=(r+l)/2;
if(check(mid))l=mid;
else r=mid;
}
printf("%.2lf\n",r);//注意这里的输出要求。
}
return 0;
}
题目七:wyh的数字
//水题
#include <iostream>
#include <algorithm>
using namespace std;
int main(void)
{
int T;
cin>>T;
while(T--)
{
string s;cin>>s;
int len=s.size();
int res=0;
for(int i=0;i<len;i++)if(s[i]=='7')res++;
cout<<res<<endl;
}
return 0;
}
题目八:wyh的数列
//找规律的题目
//从题目的a和b都很大,但是c却比较小,又是取余,可以猜出基本要找规律
//我觉得题目的描述有问题,说好1<c<1000结果样例就有个1000,说好b和a可以等于2^64,结果没有这种数据
//哎~~~!
//考虑2^64版本:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <stack>
#define ull unsigned long long
using namespace std;
const int maxn=1e4+10;
int num[maxn];
int Len[maxn];
ull fpow(ull A,ull B,ull C)//快速幂
{
ull res=1;
A%=C;
while(B)
{
if(B&1)
{
res=(res*A)%C;
}
B/=2;
A=(A*A)%C;
}
return res;
}
ull GetA(string a,ull MOD)//获取A,先对A进行长度的取余,因为2^64存不下。
{
int len=a.size();
ull res=0;
for(int i=0;i<len;i++)
res=(res*10+(a[i]-'0'))%MOD;
return res;
}
int main(void)
{
//先对所有的C进行预处理
for(int C=2;C<=1000;C++)//处理所有斐波那契数列取余C后的值的循环长度。
{
stack<int>temp;//这里要存储每个斐波那契数取余后的值,要找到有连续重复的两个就是0,1 和0,1,可以推导出来
//前面斐波那契数的余数会影响后面的斐波那契数
for(int i=0;i<=3100;i++)//这里为什么斐波那契数列的长度要取到3000呢
//是经过实验后得出的,可以每次打印最长的循环长度,如果出现了爆出的情况,就要及时进行扩大
//直到可以获得斐波那契数列取余2~1000后的全部的正确的长度
{
if(i==0)num[i]=0;
else if(i==1)num[i]=1;
else num[i]=(num[i-1]+num[i-2])%C;//这里非常重要,这里的num最后是已经是被取余1000后的
//所以后面要再写一次斐波那契数列
temp.push(num[i]);
if(temp.size()>2)//除去前两位,然后找0,1
{
int tp1=temp.top();temp.pop();
int tp2=temp.top();temp.push(tp1);
//把后面的两个拿出来看看是不是0,1
if(tp2==0&&tp1==1)break;
}
}
Len[C]=temp.size()-2;
}
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
string A,B;
ull C;cin>>A>>B>>C;
int Num_A=GetA(A,Len[C]);
//然后获取B//由于ull最多只能存储2^64-1;
//所以将B进行减一处理,这里的B可以有不同的处理方法,方便就行。
int len=B.size();
ull Num_B=0;
int flag=0;//记录有没有减去一
for(int i=0;i<len;i++)
{
if(i!=len-1){
Num_B=(Num_B*10+(B[i]-'0'))%Len[C];
}else{//这里进行的是减一的操作。
if(B[i]-'0'==0)//证明不是2^64,就不用减一,因为这种情况减去一麻烦
{
Num_B=(Num_B*10+(B[i]-'0'))%Len[C];
}else{
flag=1;
Num_B=(Num_B*10+(B[i]-'1'))%Len[C];
}
}
}
for(int i=2;i<3100;i++)num[i]=(num[i-1]+num[i-2])%C;
if(flag){//找到对应的位置,判断下有没有减一就可以输出了
cout<<num[(fpow(Num_A,Num_B,Len[C])*Num_A)%Len[C]]<<endl;
}else{
cout<<num[fpow(Num_A,Num_B,Len[C])]<<endl;
}
}
return 0;
}
//不考虑版本:
// #include <cstdio>
// #include <iostream>
// #include <algorithm>
// #include <cstring>
// #include <stack>
// #define ull unsigned long long
// using namespace std;
// const int maxn=1e4+10;
// int num[maxn];
// int Len[maxn];
// ull fpow(ull A,ull B,ull C)//快速幂
// {
// ull res=1;
// A%=C;
// while(B)
// {
// if(B&1)
// {
// res=(res*A)%C;
// }
// B/=2;
// A=(A*A)%C;
// }
// return res;
// }
// int main(void)
// {
// for(int C=2;C<=1000;C++)
// {
// stack<int>temp;
// for(int i=0;i<=3100;i++)
// {
// if(i==0)num[i]=0;
// else if(i==1)num[i]=1;
// else num[i]=(num[i-1]+num[i-2])%C;
// temp.push(num[i]);
// if(temp.size()>2)
// {
// int tp1=temp.top();temp.pop();
// int tp2=temp.top();temp.push(tp1);
// if(tp2==0&&tp1==1)break;
// }
// }
// Len[C]=temp.size()-2;
// }
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
// int T;cin>>T;
// while(T--)
// {
// ull A,B,C;
// cin>>A>>B>>C;
// for(int i=2;i<3100;i++)num[i]=(num[i-1]+num[i-2])%C;
// cout<<num[fpow(A,B,Len[C])]<<endl;
// }
// return 0;
// }
//温馨提示:全选加Ctrl+/则可去除一大批注释
题目九:wyh的天鹅
//动态找随机大,二叉平衡树的模板题
//记了模板或者有模板就随便过,虽然我调试了好久(菜是原罪)哎~~~!
//用了自己的模板结果没对,用来别人的对了,可能是模板没有考虑到重复的问题。
#include <cstdio>//这个是算法书上的模板,结果非常正确。
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int SIZE=1e7+10;
struct node
{
int lson,rson;
int val,dat;
int cnt,size;
}tree[SIZE];
int tot,root,n,INF=0x7fffffff;
int New(int val)
{
tree[++tot].val=val;
tree[tot].dat=rand();
tree[tot].cnt=tree[tot].size=1;
return tot;
}
void Update(int p)
{
tree[p].size=tree[tree[p].lson].size+tree[tree[p].rson].size+tree[p].cnt;
}
void Build()
{
New(-INF),New(INF);
root=1,tree[1].rson=2;
Update(root);
}
int GetRankByVal(int p,int val)
{
if(p==0)return 0;
if(val==tree[p].val)return tree[tree[p].lson].size+1;
if(val<tree[p].val)return GetRankByVal(tree[p].lson,val);
return GetRankByVal(tree[p].rson,val)+tree[tree[p].lson].size+tree[p].cnt;
}
int GetValByRank(int p,int rank)
{
if(p==0)return INF;
if(tree[tree[p].lson].size>=rank)return GetValByRank(tree[p].lson,rank);
if(tree[tree[p].lson].size+tree[p].cnt>=rank)return tree[p].val;
return GetValByRank(tree[p].rson,rank-tree[tree[p].lson].size-tree[p].cnt);
}
void zig(int &p)//注意这里不要抄错了,这里的l和r容易搞混。
{
int q=tree[p].lson;
tree[p].lson=tree[q].rson,tree[q].rson=p,p=q;
Update(tree[p].rson),Update(p);
}
void zag(int &p)
{
int q=tree[p].rson;
tree[p].rson=tree[q].lson,tree[q].lson=p,p=q;
Update(tree[p].lson),Update(p);
}
void Insert(int &p,int val)
{
if(p==0)
{
p=New(val);
return;
}
if(val==tree[p].val)
{
tree[p].cnt++,Update(p);
return;
}
if(val<tree[p].val)
{
Insert(tree[p].lson,val);
if(tree[p].dat<tree[tree[p].lson].dat)zig(p);
}else{
Insert(tree[p].rson,val);
if(tree[p].dat<tree[tree[p].rson].dat)zag(p);
}
Update(p);
}
int GetPre(int val)//寻找前驱(小于x的最大整数)
{
int ans=1;
int p=root;
while(p)
{
if(val==tree[p].val)
{
if(tree[p].lson>0)
{
p=tree[p].lson;
while(tree[p].rson>0)p=tree[p].rson;
ans=p;
}
break;
}
if(tree[p].val<val&&tree[p].val>tree[ans].val)ans=p;
p=val<tree[p].val?tree[p].lson:tree[p].rson;
}
return tree[ans].val;
}
int GetNext(int val)
{
int ans=2;
int p=root;
while(p)
{
if(val==tree[p].val)
{
if(tree[p].rson>0)
{
p=tree[p].rson;
while(tree[p].lson>0)p=tree[p].lson;
ans=p;
}
break;
}
if(tree[p].val>val&&tree[p].val<tree[ans].val)ans=p;
p=val<tree[p].val?tree[p].lson:tree[p].rson;
}
return tree[ans].val;
}
void Remove(int &p,int val)
{
if(p==0)return;
if(val==tree[p].val)
{
if(tree[p].cnt>1)
{
tree[p].cnt--,Update(p);
return;
}
if(tree[p].lson||tree[p].rson)
{
if(tree[p].rson==0||tree[tree[p].lson].dat>tree[tree[p].rson].dat)
zig(p),Remove(tree[p].rson,val);
else
zag(p),Remove(tree[p].lson,val);
Update(p);
}
else p=0;
return;
}
val<tree[p].val?Remove(tree[p].lson,val):Remove(tree[p].rson,val);
Update(p);
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;cin>>T;
while(T--)
{
memset(tree,0,sizeof(tree));tot=0;
Build();
int N,M;cin>>N>>M;
for(int i=0;i<N;i++)
{
int x;cin>>x;
Insert(root,x);
}
for(int i=0;i<M;i++)
{
string s;int x;cin>>s>>x;
if(s[0]=='q'){
cout<<GetValByRank(root,tree[root].size-x)<<endl;//这里的第K大用tree[root].size减一下就行,原来是求第K小的。
}else if(s[0]=='i'){
Insert(root,x);
}else{
Remove(root,x);
}
}
}
return 0;
}
题目九的另一种版本(附带完整二叉平衡树模板):
//自己捣鼓的板子,哎~~
#include <iostream>
#include <algorithm>
using namespace std;
template <typename T>
class AVL//创建则可以使用对应函数,不用build
{
public:
class node
{
public:
T key;//键值。
int data;//这里的数据类型随便改。
int height;
int cnt;//该节点及其所有子孙节点的个数
int sum;//这个节点的数量,有重复的数的时候就加进来。
node *left;
node *right;
node(T k)
{
sum=1;
height=1;
key=k;
cnt=1;
left=NULL;
right=NULL;
}
//此处可以重载大小比较符号。
};
node *root=NULL;
int n;//节点的个数。
int Get_Sum(){return Get_cnt(root);}//获取总的存储的数据的个数
void Insert(T x){root=InsertUtil(root,x);}
void Remove(T x){root=RemoveUtil(root,x);}
void InOrder(){InOrderUtil(root);cout<<endl;}//中序遍历
void PreOrder(){PreOrderUtil(root);cout<<endl;}//前序遍历
void PostOrder(){PostOrder(root);cout<<endl;}//后序遍历
int SearchRankByVal(T x){return SearchRankByValUtil(root,x,0)+1;}//查找数字的排名,里面存储的是从0开始的,所以加一(看情况)
T SearchValByRank(T x){return SearchValByRankUtil(root,x);}//查找排名对应的数字。
T Search_Next(T x){return Search_NextUtil(root,x);}//寻找一个数的后继(大于它的最小的数)
T Search_Pre(T x){return Search_PreUtil(root,x);}//寻找一个数的前驱(小于它的最大的数)
private:
int height(node* head)
{
if(head==NULL)return 0;
return head->height;
}
int Get_cnt(node *head)//获取该节点及其所有子孙节点的个数
{
if(head==NULL)return 0;
return head->cnt;
}
void Update(node *head)//更改过
{
head->height=1+max(height(head->left),height(head->right));
head->cnt=head->sum+Get_cnt(head->left)+Get_cnt(head->right);
}
node* rightRotation(node *head)
{
node *newhead=head->left;
head->left=newhead->right;
newhead->right=head;
Update(head);Update(newhead);
return newhead;
}
node *leftRotation(node *head)
{
node *newhead=head->right;
head->right=newhead->left;
newhead->left=head;
Update(head);Update(newhead);
return newhead;
}
void PreOrderUtil(node *head)//前序遍历
{
if(head==NULL)return;
cout<<head->key<<" ";
PreOrderUtil(head->left);
PreOrderUtil(head->right);
}
void InOrderUtil(node *head)//中序遍历
{
if(head==NULL)return;
InOrderUtil(head->left);
cout<<head->key<<" ";
InOrderUtil(head->right);
}
void PostOrderUtil(node *head)//后序遍历
{
if(head==NULL)return;
PostOrderUtil(head->left);
PostOrderUtil(head->right);
cout<<head->key<<" ";
}
T Search_NextUtil(node *head,T x)//找一个数的后继
{
node *temp=head;
T ans=0;
while(temp)
{
if(x>=temp->key){
temp=temp->right;
}else if(x<temp->key){//这里比它大了,要找最小的。
ans=temp->key;
temp=temp->left;
}
}
return ans;
}
T Search_PreUtil(node *head,T x)//找一个数的前驱
{
node *temp=head;
T ans=0;
while(temp)
{
if(x>temp->key){//大了就继续找,每次进行记录。
ans=temp->key;
temp=temp->right;
}else if(x<=temp->key){//小了就开始找左边。
temp=temp->left;
}
}
return ans;
}
node *InsertUtil(node *head,T x)
{
if(head==NULL)
{
n+=1;
node *temp=new node(x);
return temp;
}
if(x<head->key)head->left=InsertUtil(head->left,x);
else if(x>head->key)head->right=InsertUtil(head->right,x);
else head->sum++;
Update(head);
int bal=height(head->left)-height(head->right);
if(bal>1)
{
if(x<head->left->key)
return rightRotation(head);
else{
head->left=leftRotation(head->left);
return rightRotation(head);
}
}else if(bal<-1){
if(x>head->right->key)
return leftRotation(head);
else{
head->right=rightRotation(head->right);
return leftRotation(head);
}
}
return head;
}
node *RemoveUtil(node *head,T x)
{
if(head==NULL)return NULL;
if(x<head->key)
head->left=RemoveUtil(head->left,x);
else if(x>head->key)
head->right=RemoveUtil(head->right,x);
else{
if(head->sum==1)
{
node *r=head->right;
if(head->right==NULL)
{
node *l=head->left;
delete(head);
head=l;
}else if(head->left==NULL){
delete(head);
head=r;
}else{
while(r->left!=NULL)r=r->left;
head->key=r->key;
head->sum=r->sum;
r->sum=1;
head->right=RemoveUtil(head->right,r->key);
}
}else head->sum--;
}
if(head==NULL)return head;
Update(head);
int bal=height(head->left)-height(head->right);
if(bal>1)
{
if(height(head->left->left)>=height(head->left->right))//有进行改动
return rightRotation(head);
else{
head->left =leftRotation(head->left);
return rightRotation(head);
}
}else if(bal<-1){
if(height(head->right->right)>=height(head->right->left))
return leftRotation(head);
else{
head->right=rightRotation(head->right);
return leftRotation(head);
}
}
return head;
}
int SearchRankByValUtil(node *head,T x,int Lnum)
{
if(head==NULL)return Lnum;
if(x>head->key){
Lnum+=Get_cnt(head->left)+head->sum;
return SearchRankByValUtil(head->right,x,Lnum);
}else if(x<head->key){
return SearchRankByValUtil(head->left,x,Lnum);
}else{
Lnum+=Get_cnt(head->left);
return Lnum;
}
}
T SearchValByRankUtil(node *head,T x)
{
if(head==NULL)return -1;
if(x>Get_cnt(head->left)+head->sum){
x-=Get_cnt(head->left)+head->sum;
return SearchValByRankUtil(head->right,x);
}else if(x<=Get_cnt(head->left)){
return SearchValByRankUtil(head->left,x);
}else{
return head->key;
}
}
};
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;cin>>T;
while(T--)
{
AVL<int> tree;
int N,M;cin>>N>>M;
for(int i=0;i<N;i++)
{
int x;cin>>x;
tree.Insert(x);
}
for(int i=0;i<M;i++)
{
string s;int x;
cin>>s>>x;
if(s[0]=='q'){
cout<<tree.SearchValByRank(tree.Get_Sum()-x+1)<<endl;//题目这里是求第K大,与我们平常的排第几有点不同,要转化一下。
}else if(s[0]=='i'){
tree.Insert(x);
}else{
tree.Remove(x);
}
}
}
return 0;
}
题目十:wyh的问题
//区间dp,刚开始没想到,以为不是区间dp,因为以前做过的区间dp好像都没怎么有方向和时间,
//现在写到了就注意一下。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1500;
const int INF=0x3f3f3f3f;
int dp[maxn][maxn][2];//最后一维代表最后停在i还是j。0为i,1为j。
//i和j分别表示走过的左右两边。如果最后停在i证明是从i+1过来的,因为i到j要都走过,并且停在i,所以是从i过来的。
int D[maxn],W[maxn];
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int N;
while(cin>>N)
{
memset(dp,INF,sizeof(dp));
int V;cin>>V;//预处理能量区间
for(int i=1;i<=N;i++)
{
cin>>D[i]>>W[i];
W[i]+=W[i-1];
}
dp[V][V][1]=dp[V][V][0]=0;
for(int len=2;len<=N;len++)
{
for(int i=1;i+len-1<=N;i++)
{
int j=i+len-1;
dp[i][j][0]=min(dp[i+1][j][0]+(D[i+1]-D[i])*(W[i]+W[N]-W[j]),dp[i+1][j][1]+(D[j]-D[i])*(W[i]+W[N]-W[j]));
//之所以不向其的的区间dp一样是因为,只能往左右延申,不能先合成一部分的,是有牵扯的,只能一步一步合成
//没有一次可以移动两个的。
dp[i][j][1]=min(dp[i][j-1][1]+(D[j]-D[j-1])*(W[i-1]+W[N]-W[j-1]),dp[i][j-1][0]+(D[j]-D[i])*(W[i-1]+W[N]-W[j-1]));
}
}
cout<<min(dp[1][N][0],dp[1][N][1])<<endl;
}
return 0;
}
(完结,能力不足,不足以支撑其他的题目,主要是懒)
作者:WUTONGHUA02
-------------------------------------------
个性签名:啊啊啊,敲代码真的是太难了!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
努力努力,再努力,哈哈哈(っ•̀ω•́)っ✎⁾⁾!