zoukankan      html  css  js  c++  java
  • 2018中国大学生程序设计竞赛

    传送门

    A.HDU6438 Buy and Resell

    题意

    给你N天N个价格,每天都可以从1.买入一个,2.卖出一个,3.什么都不做,求最高获利

    低买高卖问题,这题与其他的差距就是要在满足获利最多的情况下,买卖次数最小;

    思路

    手算一下发现价格具有传递性;例如数据是1,5,9;
    5的时候买入1赚了4;9的时候买入5赚了4;相当于直接把5当成跳板直接9的时候买1;然后再把中间的5当成没有买过的;

    建立一个小根堆(优先队列);把当前遇到的天数的价钱放入,然后对于第i天;

    1.如果新天数的价钱比堆顶小;说明交易亏本,直接丢入堆中;
    2.如果价钱高说明有赚头;
    2.1.如果堆顶的是已经跟之前的交易过的,那相当于当前天和之前的那个交易,然后堆顶的变成没有交易的;继续插入;交易次数不变
    2.2否则直接交易,交易次数+2

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=1e6+50;
    const ll inf=0x3f3f3f3f3f3f;
    int a[maxn];
    struct node{
        int id;
        int money;
        bool has;
        node(int id,int money,bool has):id(id),money(money),has(has){}
        bool friend operator <(node a,node b){
            if(a.money==b.money)return a.has<b.has;
            return a.money>b.money;
        }
    };
    int flag[maxn];
    int used[maxn];
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int t;
        cin>>t;
        while(t--){
            int n;
            cin>>n;
            ll ans=0;
            ll cnt=0;
            memset(flag,0,sizeof(flag));
            memset(used,-1,sizeof(used));
            for(int i=0;i<n;i++)cin>>a[i];
            priority_queue<node>pq;
            for(int i=0;i<n;i++){
                if(pq.empty())pq.push(node(i,a[i],0));
                else{
                    node now=pq.top();
                    if(now.money>=a[i])pq.push(node(i,a[i],0));
                    else{
                        pq.pop();
                        if(flag[now.id]){
                            ans+=a[i]-now.money;
                            flag[i]=1;flag[now.id]=0;
                            used[i]=used[now.id];
                            used[now.id]=-1;
                            pq.push(node(i,a[i],1));
                            pq.push(node(now.id,a[now.id],0));
                        }
                        else{
                            ans+=a[i]-now.money;
                            cnt+=2;
                            flag[i]=1;flag[now.id]=1;
                            used[i]=now.id;
                            pq.push(node(i,a[i],1));
                        }
                    }
                }
            }
            cout<<ans<<" "<<cnt<<endl;
        }
        return 0;
    }
    

    C.HDU6440 Dream

    题意

    对一个质数P,对小于P的非负数定义一种乘法和加法运算,使得其满足封闭性,且对于存在一个数q使得{qk|0< k< p}

    思路

    费马小定理,比赛随便迷一样的试了一下就A了,自己也不知道怎么解释...

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    const int maxn=1e5+50;
    const ll inf=0x3f3f3f3f3f3f;
    int n;
    int vis[maxn];
    int size[maxn];
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int t;
        cin>>t;
        while(t--){
            int p;
            cin>>p;
            for(int i=0;i<p;i++){
                cout<<i;
                for(int j=1;j<p;j++){
                    cout<<" "<<(i+j)%p;
                }
                cout<<endl;
            }
    
            for(int i=0;i<p;i++){
                cout<<0;
                for(int j=1;j<p;j++){
                    cout<<" "<<(i*j)%p;
                }
                cout<<endl;
            }
    
        }
        return 0;
    }
    

    D.HDU6441 Find Integer

    题意

    题意:已知an+bn=c^n,给出n和a,求b,c,如果无解输出−1。

    思路

    费马大定理

    1. an+bn=c^n,n>2时无解。
    2. 当a为奇数时,
      a=2⋅k+1
      c=k2+(k+1)2
      b=c−1
      3.当 a 为偶数
      a=2∗k+2
      c=1+(k+1)^2
      b=c−2
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=3e6+50;
    const ll inf=0x3f3f3f3f3f3f;
    
    int main()
    {
        //std::ios::sync_with_stdio(false);
       // std::cin.tie(0);
        //std::cout.tie(0);
        int t;
        scanf("%d",&t);
        while(t--){
            ll n,a;
            scanf("%lld%lld",&n,&a);
            if(n==0){
                printf("-1 -1
    ");
            }
            else if(n==1){
                printf("1 %lld
    ",a+1);
            }
            else if(n==2)
                {
                    if(a&1){
                        printf("%lld %lld
    ",a*a/2,a*a/2+1);
                    }
                    else{
                        printf("%lld %lld
    ",(a/2)*(a/2)-1,(a/2)*(a/2)+1);
                    }
                }
            else{
                printf("-1 -1
    ");
            }
        }
        return 0;
    }
    

    I.HDU6446 Tree and Permutation

    题意

    题意:给你一颗树,然后让你求n!种序列中,所以得序列和,序列和定义为:A1,A2,A3……AN=A1A2+A2A3+…….An-1An

    思路

    首先,对于题目给出的n-1条边,我们可以这样考虑,去掉这条边后,将树分成了两部分,一部分有M个节点,另一部分有(N-M)个节点,所以我们必须在这两块中任意选择一个节点才会进过这条边,所以,有N × M× 2 中选择,然后又N!个序列所以对于E这条边,一共又2×N×M×(N-1)!×L的贡献。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    const int maxn=1e5+50;
    const ll inf=0x3f3f3f3f3f3f;
    int n;
    int vis[maxn];
    int size[maxn];
    struct Edge{
        int to;
        int s;
        int t;
        int l;
        Edge(int to,int s,int t,int l):to(to),s(s),t(t),l(l){}
    };
    ll f[maxn];
    int init(){
        f[0]=1;f[1]=1;
        for(int i=2;i<=100000;i++)f[i]=(f[i-1]*i)%mod;
    }
    ll ans;
    vector<Edge>G[maxn];
    void dfs(int u){
        vis[u]=1;
        int cnt=1;
        for(int i=0;i<G[u].size();i++){
            Edge &e=G[u][i];
            if(vis[e.to]==0){
                dfs(e.to);
                ll tmp=size[e.to];
                tmp=tmp*(n-tmp)%mod;
                tmp=tmp*2%mod;
                tmp=tmp*e.l%mod;
                tmp=tmp*f[n-1]%mod;
                ans+=tmp;
                ans%=mod;
                cnt+=size[e.to];
            }
        }
        size[u]=cnt;
    }
    
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int t;
        init();
        while(cin>>n){
            for(int i=0;i<=n;i++)G[i].clear();
            for(int i=0;i<=n;i++)size[i]=0,vis[i]=0;
            ans=0;
            for(int i=0;i<n-1;i++){
                ll x,y,l;
                cin>>x>>y>>l;
                G[x].push_back(Edge(y,x,y,l));
                G[y].push_back(Edge(x,x,y,l));
            }
            dfs(1);
            cout<<ans<<endl;
        }
        return 0;
    }
    

    J.HDU6447 YJJ's Salesman

    题意

    题意:一个地图,里面有最多1e5个村庄,YJJ从0,0开始走,只能向左,下,左下走,如果向左下走进一个村庄那就能获得这个村庄的价值;求最大价值;从(0,0)到(n,n);
    数据范围1e9!数组装不下

    思路

    首先题意是求最大值,最基本的DP模型是三个方向的最大值;但是复杂度会爆炸而且也开不了那么大的数组;
    1.离散化坐标;因为1e9的坐标范围太大数组装不下,但是只有1e5的村庄,所以可以把1e9离散化到1e5里面;

    2.每次搜索前面的最大值;利用树状数组搜索到当前位置的J坐标之前的最大值然后加上当前值再添加进树状数组

    比赛的时候离散完,想吧坐标压缩成一维的可是没想到办法所以凉凉了,其实这题不用压缩直接按照x的坐标从小到大排序,然后按照同一行从大到小排序就行了;

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=1e5+50;
    const int maxm=1e5+50;
    const ll inf=0x3f3f3f3f3f3f;
    int N;
    struct node{
        int x,y,value;
    };
    int cmp(node a,node b){
        if(a.x==b.x)return a.y>b.y;
        return a.x<b.x;
    }
    int c[maxm];
    inline int lowbit(int x){return x&(-x);}
    void update(int x,int p){
        for(int i=x;i<maxn;i+=lowbit(i)){
            c[i]=max(c[i],p);
        }
    }
    int query(int x){
        int ma=0;
        for(int i=x;i>0;i-=lowbit(i)){ma=max(ma,c[i]);}
        return ma;
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int t;
        cin>>t;
        while(t--){
            int n;
            cin>>n;
            vector<node>ve;
            vector<int>k;
            k.push_back(-1);
            memset(c,0,sizeof(c));
            for(int i=0;i<n;i++){
                node a;
                cin>>a.x>>a.y>>a.value;
                ve.push_back(a);
                k.push_back(a.y);
            }
            sort(k.begin(),k.end());
            sort(ve.begin(),ve.end(),cmp);
            k.erase(unique(k.begin(),k.end()),k.end());
            N=k.size();
            int anw=0;
            for(int i=0;i<n;i++){
                int ans=lower_bound(k.begin(),k.end(),ve[i].y)-k.begin();
                int cnt=query(ans-1);
                cnt+=ve[i].value;
                update(ans,cnt);
                anw=max(anw,cnt);
            }
            cout<<anw<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    matlab练习程序(单源最短路径Bellman-Ford)
    matlab练习程序(广度优先搜索BFS、深度优先搜索DFS)
    matlab练习程序(模拟退火SA)
    matlab练习程序(演化策略ES)
    matlab练习程序(差异演化DE)
    matlab练习程序(粒子群优化PSO)
    安卓Webview缓存网页数据(无网络正常显示)
    Git之Github使用(一):Push代码到Github
    SuperIndicator 一个专用打造轮播的类库
    android的多次点击事件的实现(有源码)
  • 原文地址:https://www.cnblogs.com/luowentao/p/10332188.html
Copyright © 2011-2022 走看看