多校赛2017 R1

2 篇文章 0 订阅
1 篇文章 0 订阅

#多校赛2017#

HDU 6044

Problem

As to a permutation p1,p2,⋯,pn from 1 to n, it is uncomplicated for each 1≤i≤n to calculate (li,ri) meeting the condition that min(pL,pL+1,⋯,pR)=pi if and only if li≤L≤i≤R≤ri for each 1≤L≤R≤n.

Given the positive integers n, (li,ri) (1≤i≤n), you are asked to calculate the number of possible permutations p1,p2,⋯,pn from 1 to n, meeting the above condition.

The answer may be very large, so you only need to give the value of answer modulo 109+7.

题意

给n个L,R对,对于第i个对,表示其在(al, a(l+1),…ar)中为最小值,问有多少种(1…n)的置换满足条件。

思路

不考虑数字的组合方式,对于给定的LR对生成的二叉树唯一,直接搜索即可。L升序R降序快排后发现,此时LR序列正好为二叉树的先序遍历结果!(贼关键)

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

namespace fastIO {
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline void read(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror)
            return;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }
    #undef BUF_SIZE
};
const int maxn = 1000005, mod = 1e9 + 7;
int fact[maxn], inv[maxn];
struct nd {
    int a, b, pos;
    bool operator < (const nd &_nd) const{
        if(a == _nd.a) {
            return b >= _nd.b;
        }
        return a < _nd.a;
    }
} a[maxn];
int apos = 0;
int gg = 0;

int C(int n, int m) {
    return (LL)fact[n] * (LL)inv[n-m] % mod * (LL)inv[m] % mod;
}

int solve(int l, int r) {
    if(gg) return 0;
    if(l > r) return 1;
    if(a[apos].a != l || a[apos].b != r) {
        gg = 1; return 0;
    }
    nd t = a[apos];
    apos++;
    if(l == r) return 1;
    LL res = 1LL * C(t.b - t.a, t.pos - t.a) * solve(t.a,t.pos-1) % mod;
    res = res * solve(t.pos + 1, t.b) % mod;
    return (int)res;
}

int main() {
    inv[1] = 1;
    for(int i = 2; i < maxn; ++i)
        inv[i] = mod - (int)(mod / i * (LL)inv[mod % i] % mod);
    fact[0] = inv[0] = 1;
    for(int i = 1; i < maxn; ++i)
    {
        fact[i] = (LL)fact[i - 1] * i % mod;
        inv[i] = (LL)inv[i - 1] * inv[i] % mod;
    }
    int n, cs = 1;
    while(fastIO::read(n), !fastIO::IOerror) {
        for(int i = 0; i < n; i++) fastIO::read(a[i].a);
        for(int i = 0; i < n; i++) {
            fastIO::read(a[i].b);
            a[i].pos = i + 1;
        }
        //LR对排序后的序列即是先序遍历结果
        sort(a, a + n);
        apos = gg = 0;
        printf("Case #%d: %d\n",cs++,solve(1,n));
    }
}

HDU 6040

Problem

sd0061, the legend of Beihang University ACM-ICPC Team, retired last year leaving a group of noobs. Noobs have no idea how to deal with m coming contests. sd0061 has left a set of hints for them.

There are n noobs in the team, the i-th of which has a rating ai. sd0061 prepares one hint for each contest. The hint for the j-th contest is a number bj, which means that the noob with the (bj+1)-th lowest rating is ordained by sd0061 for the j-th contest.

The coach asks constroy to make a list of contestants. constroy looks into these hints and finds out: bi+bj≤bk is satisfied if bi≠bj, bi

题意

给1e7个数,有100次查询,每次求第bi+1小的数,bi相当于斐波那契数列,这样就可以做到每次查询的范围缩小1.618倍,然后复杂度就是Sigma(n/1.618^i),其实就是求个等比数列。

思路

会求复杂度就敢搞了。

#include<bits/stdc++.h>

using namespace std;

typedef pair<int, int> p;
unsigned res[105];
unsigned x, y, z;
const int SIZE = 10000001;
unsigned aa[SIZE];
p ma[SIZE];

unsigned rng61() {
  unsigned t;
  x ^= x << 16;
  x ^= x >> 5;
  x ^= x << 1;
  t = x;
  x = y;
  y = z;
  z = t ^ x ^ y;
  return z;
}

int main() {
    int n, m, a, b, c;
    int cs = 1;
    while(~scanf("%d%d%d%d%d",&n,&m,&a,&b,&c)) {
        x = a; y = b; z = c;
        for(int i = 0; i < n; i++) aa[i] = rng61();
        for(int i = 0; i < m; i++) {
            scanf("%d",&ma[i].first);
            ma[i].second = i;
        }
        sort(ma,ma + m);
        ma[m] = p(n,n);
        for(int i = m - 1; i >= 0; i--) {
            nth_element(aa, aa + ma[i].first, aa + ma[i+1].first);
            //
            res[ma[i].second] = aa[ma[i].first];
        }
        printf("Case #%d:",cs++);
        for(int i = 0; i < m; i++) printf(" %u",res[i]);
        puts("");
    }
    return 0;
}

HDU 6041

Problem

There is a connected undirected graph with weights on its edges. It is guaranteed that each edge appears in at most one simple cycle.

Assuming that the weight of a weighted spanning tree is the sum of weights on its edges, define V(k) as the weight of the k-th smallest weighted spanning tree of this graph, however, V(k) would be defined as zero if there did not exist k different weighted spanning trees.

Please calculate (∑k=1Kk⋅V(k))mod232.

题意

仙人掌图,求1到k小的最小生成树权值和。

思路

点双连通优先队列暴搞看脸A。

#include<stack>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
vector<int> res;
int K;

struct nd {
    int w, x, y;
    bool operator < (const nd& _nd) const {
        return w < _nd.w;
    }
};

vector<int> sv;
void Solve(vector<int> &va, vector<int> &vb) {
    priority_queue<nd> pq;
    for(int i = 0; i < vb.size(); i++) {
        pq.push((nd) {va[0] + vb[i], 0, i});
    }
    sv.resize(0);
    while(sv.size() < K && !pq.empty()) {
        nd nt = pq.top(); pq.pop();
        sv.push_back(nt.w);
        if(nt.x + 1 < va.size()) {
            nt.x ++;
            pq.push((nd) {va[nt.x] + vb[nt.y], nt.x, nt.y});
        }
    }
    va = sv;
}

const int MAXN = 1010;
const int MAXM = 5000;

struct Edge
{
    int to,next,val;
} edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN];//,Stack[MAXN],Belong[MAXN];

int Index,top;
int block;//点双连通分量的个数
//bool Instack[MAXN];

void addedge(int u,int v,int val)
{
    edge[tot].to = v;edge[tot].next = head[u];edge[tot].val = val;head[u] = tot++;
}

stack<int> st;
void Tarjan(int u,int pre = -1)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    //Stack[top++] = u;
    //Instack[u] = true;
    for(int i = head[u];i != -1;i = edge[i].next)
    {
        v = edge[i].to;
        //if(v == pre)continue;
        if( !DFN[v] )
        {
            st.push(i);
            Tarjan(v,u);
            if(Low[u] > Low[v])Low[u] = Low[v];
            if( Low[v] >= DFN[u])
            {
                block++;
                int ii;
                vector<int> t2;
                do
                {
                    //vn = Stack[--top];
                    //Belong[vn] = block;
                    //Instack[vn] = false;
                    ii = st.top();
                    st.pop();
                    t2.push_back(edge[ii].val);
                }
                while( ii!=i );

               // cout << t2.size() << endl;
               // for (auto &x : t2) cout << x << ' '; cout << endl;

                if(t2.size() > 1) Solve(res, t2);
            }
        }
        else if(v!=pre && DFN[v] < DFN[u]) {
            st.push(i);
            Low[u] = min(Low[u], DFN[v]);
        }
//        else if(Instack[v] && Low[u] > DFN[v])
//        {
//            Low[u] = DFN[v];
//            st.push(i);
//        }
    }
}
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

int main(){
    //freopen("1009.in","r",stdin);
    int n, m, cs = 1;
    res.reserve(100005);
    sv.reserve(100005);
    while(~scanf("%d%d",&n,&m)) {
        init();
        int x, y, z;
        int sum = 0;
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
            addedge(y,x,z);
            sum += z;
        }
        res.resize(0);
        res.push_back(0);
        scanf("%d",&K);
        memset(DFN,0,sizeof(DFN));
        //memset(Instack,false,sizeof(Instack));
        //memset(Belong,0,sizeof(Belong));
        Index = block = top = 0;
        Tarjan(1);
        unsigned r = 0;
        for(int i = 0; i < res.size(); i++) {
            r += (unsigned)(i + 1) * (unsigned)(sum - res[i]);
        }
        printf("Case #%d: %u\n",cs++,r);
        //if(n == 28) return 0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值