2018 CCPC 网络赛 (待更新) HDU 6438 ~ 6447

10 篇文章 0 订阅
7 篇文章 0 订阅

2018 CCPC 网络赛 (待更新) HDU 6438 ~ 6447


莫干山半日游,体验略差啊、、


AC情况
题号1001100210031004100510061007100810091010
XXXXX

(1001) HDU 6438 Buy and Resell

题目链接
题意:

商人能在N个地方以 ai a i 的价格买入或卖出商品,在每个地方只能做一次交易。要求最大的收益,同时最小化交易次数。

思路:

贪心。用优先队列维护一个可买入的序列以及一个已经卖出的队列(还可以反悔tao),分类讨论即可。

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>


using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back

const int MAXN = 200005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;

int _;

using namespace std;

priority_queue<ll, vector<ll>, greater<ll>> sell;
priority_queue<ll, vector<ll>, greater<ll>> resell;


int main()
{
    //freopen("input","r",stdin);
    //freopen("output","w+",stdout);
    cin>>_;
    while(_--)
    {
        int N;
        scanf("%d",&N);
        ll ans = 0LL;
        ll times = 0LL;
        ll item;
        while(!sell.empty())    sell.pop();
        while(!resell.empty())    resell.pop();

        for(int i=1;i<=N;++i)
        {
            scanf("%I64d",&item);
            if(!resell.empty())
            {
                ll least_sold = resell.top();
                if(!sell.empty()&&sell.top()<least_sold&&least_sold<item)
                {
                    times += 2;
                    ans += item;
                    resell.push(item);
                    sell.pop();
                }
                else if(least_sold<item)
                {
                    resell.pop();
                    ans -= least_sold*2LL;
                    ans += item;
                    sell.push(least_sold);
                    resell.push(item);
                }
                else if(!sell.empty()&&sell.top()<item)
                {
                    times += 2;
                    ans += item;
                    resell.push(item);
                    sell.pop();
                }
                else
                {
                    sell.push(item);
                    ans -= item;
                }
            }else if(!sell.empty()&&sell.top()<item)
            {
                times += 2;
                ans += item;
                resell.push(item);
                sell.pop();
            }else
            {
                sell.push(item);
                ans -= item;
            }
        }
        while(!sell.empty())    ans += sell.top(), sell.pop();
        printf("%I64d %I64d\n",ans,times);
    }
    return 0;
}

(1003) HDU 6440 Dream

题目链接
题意:

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

思路:

易得,对于一个质数p,模p意义下 2k%p 2 k % p 可以构成一个 {k|0<k<p} { k | 0 < k < p } ,不妨将乘法定义为 ij=(ij)%p i ∗ j = ( i ∗ j ) % p ,同时为了简便将加法定义为 i+j=i i + j = i ,显然满足条件。

AC代码:
// by Yongqiang Chen
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>


using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back

const int MAXN = 100005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;

int _;

using namespace std;



int main()
{
    //freopen("input","r",stdin);
    //freopen("output","w+",stdout);

    cin>>_;
    while(_--)
    {
        int P;
        scanf("%d",&P);
        for(int i=0;i<P;++i)
        {
            for(int j=0;j<P-1;++j)
                printf("%d ",i);
            printf("%d\n",i);
        }
        for(int i=0;i<P;++i)
        {
            for(int j=0;j<P-1;++j)
                printf("%d ",(i*j)%P);
            printf("%d\n",(i*(P-1))%P);
        }
    }

    return 0;
}

(1004) Find Integer

题目链接:无补题链接
题意:

给定n, a,解方程 an+bn=cn a n + b n = c n 输出b和c。

思路:

n大于3无解,讨论n为2和1的情况即可。

AC代码:
#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
    long long a, b, c;
    int t;
    cin >> t;
    long long n;
    while(t--){
        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){
            printf("-1 -1\n");
        }else{
            long long mul = a*a;
            if(mul & 1){
                printf("%lld %lld\n", (mul-1)/2, (mul+1)/2);
            }else{
                b = (mul-4)/4;
                c = b+2;
                printf("%lld %lld\n", b, c);
            }
        }
    }
    return 0;
}

(1009) HDU 6446 Tree and Permutation

题目链接
题意:

给一棵N个点的树,对应于一个长为N的全排列,对于排列的每个相邻数字a和b,他们的贡献是对应树上顶点a和b的路径长,求所有排列的贡献和。

思路:

随手画几颗树,统计一下树上所有点对对于答案的贡献,发现存在规律。

a[1]=0 a [ 1 ] = 0
a[2]=2 a [ 2 ] = 2
i>=3a[i]=a[i1](i1), i >= 3 时 , a [ i ] = a [ i − 1 ] ∗ ( i − 1 ) ,

那么只需要DFS一遍树上所有点对路径之和再乘上a[N]即可。DFS时,每条边对路径和的贡献是连接该边左右子树大小之积。

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>


using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back

const int MAXN = 100005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;

int _;

using namespace std;

int N;
int head[MAXN];
int curedgeno;

struct Edge{
    int u, v, w;
    int next;
    Edge(int u=0, int v=0, int w=0, int next=-1): u(u), v(v), w(w), next(next) {}
}edge[MAXN<<1];

void init()
{
    memset(head,-1,sizeof(head));
    curedgeno = 0;
}

void add_edge(int u, int v, int w)
{
    ++curedgeno;
    edge[curedgeno] = Edge(u,v,w);
    edge[curedgeno].next = head[u];
    head[u] = curedgeno;
}

ll num[MAXN];
int mk[MAXN];
ll tot_sum;
// return the sum of sub tree
ll dfs(int u, int fa)
{
    mk[u] = 1;
    ll cnt = 1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int  v = edge[i].v;
        if(!mk[v]&&v!=fa)
        {
            ll tmp = dfs(v,u);
            cnt += tmp;
            tot_sum = (tot_sum+tmp*(N-tmp)%MOD*(ll)edge[i].w%MOD)%MOD;
        }
    }
    return cnt;
}



int main()
{
    //freopen("input","r",stdin);
    //freopen("output","w+",stdout);
    num[1] = 0;
    num[2] = 2;
    num[3] = 4;
    for(int i=4;i<MAXN;++i)
        num[i] = num[i-1]*(ll)(i-1)%MOD;
    while(scanf("%d",&N)!=EOF)
    {
        init();
        int u, v, w;
        memset(mk,0,sizeof(mk));
        for(int i=1;i<N;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        tot_sum = 0LL;
        dfs(1,-1);
        //cout<<tot_sum<<endl;
        printf("%lld\n",tot_sum*num[N]%MOD);
    }
    return 0;
}

(1010) HDU 6447 YJJ’s Salesman

题目链接
题意:

二维平面上N个点,从(0,0)出发到(1e9,1e9),每次只能往右,上,右上三个方向移动,
该N个点只有从它的左下方格点可达,此时可获得收益。求该过程最大收益。

思路:

首先联想到一个DP,设 dp[i][j] d p [ i ] [ j ] 为到达即对每个点 (i,j) ( i , j ) ,到达该点的最大收益为 max(dp[i][j]+val[i][j]) m a x ( d p [ i ′ ] [ j ′ ] + v a l [ i ] [ j ] ) ,复杂度为 O(N2) O ( N 2 ) ,不管是时间还是空间都不允许。
不妨利用坐标信息,将所有点离散化之后,将x作为第一关键字从小到大,y作为第二关键字从大到小排序,此时维护一个 dp[i] d p [ i ] 表示到 y=i y = i 时可以获得的最大收益,那么有

j=0i1 j = 0 → i − 1
dp[i]max(dp[i[,dp[j]+val) d p [ i ] ← m a x ( d p [ i [ , d p [ j ] + v a l )

因为x已经按从小到大排好序了,y也是从大到小更新的,故保证了可达性。
对于每次更新,可以用线段树或者树状数组维护最大值,此时算法复杂度 O(NlogN) O ( N l o g N )

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>


using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define pb push_back

const int MAXN = 200005;
const ll MOD = 1e9+7;
const int INF = 1e9+7;

int _;

using namespace std;

struct Point{
    int x, y, w;
    Point() {}
    Point(int _x, int _y, int _w):x(_x),y(_y),w(_w) {}
    void read()
    {
        scanf("%d%d%d",&x,&y,&w);
    }
    void show()
    {
        printf("%d %d\n",x,y);
    }
}points[MAXN];

bool operator<(const Point& a, const Point& b)
{
    return a.x==b.x?a.y>b.y:a.x<b.x;
}

int N;

// Discretization
int hashx[MAXN], hashy[MAXN];

void gomapping()
{

    for(int i=1;i<=N;++i)
    {
        hashx[i] = points[i].x;
        hashy[i] = points[i].y;
    }
    sort(hashx+1,hashx+1+N);
    sort(hashy+1,hashy+1+N);
    int cntx = unique(hashx+1,hashx+1+N) - hashx;
    int cnty = unique(hashy+1,hashy+1+N) - hashy;
    for(int i=1;i<=N;++i)
    {
        points[i].x = lower_bound(hashx+1,hashx+1+cntx,points[i].x) - hashx;
        points[i].y = lower_bound(hashy+1,hashy+1+cnty,points[i].y) - hashy;
    }
    //for(int i=1;i<=N;++i)   points[i].show();
}

int dp[MAXN];

int tree[MAXN];

inline int lowbit(int x) { return x&-x; }


void update(int pos, int val)
{
    while(pos <= N)
    {
        tree[pos] = dp[pos];
        for(int i=1;i<lowbit(pos);i<<=1)
            tree[pos] = max(tree[pos],tree[pos-i]);
        pos += lowbit(pos);
    }
}

int query(int l, int r)
{
    int ans = 0;
    while(r>=l)
    {
        ans = max(ans,dp[r]);
        if(l==r)    break;
        for(--r;r-l>=lowbit(r);r-=lowbit(r))
            ans = max(ans,tree[r]);
    }
    return ans;
}

int main()
{
    //freopen("input","r",stdin);
    //freopen("output","w+",stdout);
    cin>>_;
    while(_--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;++i)   points[i].read();
        sort(points+1,points+1+N);
        gomapping();
        int cur = 1;
        memset(tree,0,sizeof(tree));
        memset(dp,0,sizeof(dp));
        while(cur<=N)
        {
            int curx = points[cur].x;
            while(cur<=N&&(curx = points[cur].x))
            {
                dp[points[cur].y] =
                    max(dp[points[cur].y],
                    query(1,points[cur].y-1)+points[cur].w);
                update(points[cur].y,dp[points[cur].y]);
                cur++;
            }

        }
        int ans = 0;
        for(int i=1;i<=N;++i)
            ans = max(ans,dp[i]);
        printf("%d\n",ans);
    }
    return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值