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

(完结,能力不足,不足以支撑其他的题目,主要是懒)

posted @ 2023-03-13 19:33  WUTONGHUA02  阅读(19)  评论(0编辑  收藏  举报