1. 程式人生 > >2018中國大學生程序設計競賽 - 網絡選拔賽

2018中國大學生程序設計競賽 - 網絡選拔賽

小根堆 其他 scanf http money while () bit out

傳送門

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

題意

題意:已知a^n+b^n=c^n,給出n和a,求b,c,如果無解輸出?1。

思路

費馬大定理

  1. a^n+b^n=c^n,n>2時無解。
  2. 當a為奇數時,
    a=2?k+1
    c=k^2+(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\n");
        }
        else if(n==1){
            printf("1 %lld\n",a+1);
        }
        else if(n==2)
            {
                if(a&1){
                    printf("%lld %lld\n",a*a/2,a*a/2+1);
                }
                else{
                    printf("%lld %lld\n",(a/2)*(a/2)-1,(a/2)*(a/2)+1);
                }
            }
        else{
            printf("-1 -1\n");
        }
    }
    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;
}

2018中國大學生程序設計競賽 - 網絡選拔賽