哈尔滨理工大学软件学院ACM程序设计全国邀请赛

来源:互联网 发布:新闻中心数据库设计 编辑:程序博客网 时间:2024/04/27 21:29

哈尔滨理工大学软件学院ACM程序设计全国邀请赛

A Golds

Description

Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. There are N metal mineral. In i-th (1<=i<=N) metal mineral, there are a[i] golds. Now Humans launches m robots on Mars to collect golds. The i-th (1<=i<=m) robot can collect golds on path from s[i] to e[i], and at most collect w[i] golds. We want to know the maximum total golds that can be collected by m robots.

Input

There are multiple cases in the input. In each case:

The first line specifies three integers N, m specifying the numbers of metal mineral and the number of robots. (1 <= N <= 2000,1<=m<=2000)

The next line will give N integers. a[i] (1<=i<=N) means there are a[i] golds on i-th metal mineral.(0 <= a[i] <= 10000)

The next n‐1lines will give two integers u,v in each line specifyingthere is a path connected point u and v.(1<=u<=N,1<=v<=N, u != v)

The next m lines will give there integers s[i], e[i], w[i] in eachline specifying the i-th robot can collect golds on path from s[i] to e[i], andat most collect w[i] golds. (1<=s[i]<=N, 1<=e[i]<=N,0<=w[i]<=20000000).

Output

For each case, output the maximum total golds that can be collected.

分析

考虑最大流。

建图如下:

src = 0, sink = n+m+1;

1~m → robots id

m+1 ~ m+n →metal mineral id

由源点src向n个矿点连边,流量为a[i]。由m个robots向汇点sink连边,流量为w[i].

对于每一个robots,通过DFS查找s[i]→e[i]路径上的所有矿点,上述矿点均向对应robot连边,流量为inf。此处单次搜索复杂度为O(n),总体为O(nm)

代码

#include<bits/stdc++.h>using namespace std;const int inf = 1e9 + 7;    const int maxv = 4000 + 10; const int maxn = 2000 + 10;//------------最大流Dinic模板------------//struct Edge {    int to,cap,rev;    Edge(){};    Edge(int _to,int _cap,int _rev) {        to = _to;   cap = _cap; rev = _rev;    }};vector<Edge> G[maxv];int level[maxv];int iter[maxv];void addedge(int from,int to,int cap) {     G[from].push_back(Edge(to, cap, G[to].size()));    G[to].push_back(Edge(from, 0, G[from].size()-1));}void bfs(int s) {    memset(level,-1,sizeof(level));    queue<int> que;    level[s] = 0;    que.push(s);    while(!que.empty()) {        int v = que.front();        que.pop();        for(int i=0;i<G[v].size();i++) {            Edge &e = G[v][i];            if(e.cap > 0 && level[e.to] < 0) {                level[e.to] = level[v] + 1;                que.push(e.to);            }        }    }}int dfs(int v,int t,int f) {    if(v == t)  return f;    for(int &i=iter[v];i < G[v].size();i++) {        Edge &e = G[v][i];        if(e.cap > 0 && level[v] < level[e.to]) {            int d = dfs(e.to,t,min(f,e.cap));            if(d > 0) {                e.cap -= d;                G[e.to][e.rev].cap += d;                return d;            }        }    }    return 0;}int maxflow(int s,int t) {    int flow = 0;    while(true) {        bfs(s);        if(level[t] < 0)    return flow;        memset(iter,0,sizeof(iter));        int f;        while((f = dfs(s,t,inf)) > 0)            flow += f;    }}//-------------end----------------------//int en,n,m;Edge e;vector<Edge> g[maxn];void add(int u,int v){    e.to = v,   g[u].push_back(e);    e.to = u,   g[v].push_back(e);}bool DFS(int s,int fa,int lnk){    if(s == en) return true;    for(int i=0,to;i<g[s].size();i++){        to = g[s][i].to;        if(to == fa)    continue;        if(DFS(to,s,lnk)){            addedge(to+m,lnk,inf);            return true;        }    }    return false;}void addEDGE(int s,int e,int lnk){    en = e;    DFS(s,-1,lnk);    addedge(s+m,lnk,inf);}void init() {    for(int i=0;i<maxv;i++)        G[i].clear();    for(int i=0;i<maxn;i++)        g[i].clear();}int main(){    for(;scanf("%d %d",&n,&m)!=EOF;){        init();        for(int i=1,a;i<=n;i++)            scanf("%d",&a),  addedge(0,i+m,a);        for(int i=1,u,v;i<n;i++)            scanf("%d %d",&u,&v),   add(u,v);        for(int i=1,s,e,w;i<=m;i++){            scanf("%d %d %d",&s,&e,&w);            addedge(i,n+m+1,w);            addEDGE(s,e,i);        }        printf("%d\n",maxflow(0,n+m+1));    }}

C Coin

Description

Bob will go to buy book. The price of this book is M.So Bob will take N coins, and the total value equals M. But the actual price for this book maybe less than M. Bob wish the N coins can combined into all value that less than M. Each coin’s value can be any positive integer. Could you tell me how many kinds of coin set that Bob can take. Because the total solution can be quite large, so please mod 2000000007.

Input

The first line contains an integer T (T <= 200), which is the number of cases.

Followed by T lines, each line contains two integersN,M(N,M<=200).

Output

For each case, output the number of solution

分析

用dp[i][j][k]表示用i枚硬币能够支付1~j的任意金额,且最大面额硬币为k的方案数量。

保证枚举时的k大于等于其前置方案的k值即不会计重。

代码

#include<bits/stdc++.h>using namespace std;const int N = 200 + 1;const int mod =2e9 + 7;long long dp[N][N][N],ans;int main(){    dp[1][1][1] = 1;    for(int i=1;i<N;i++)    for(int j=1;j<N;j++)    for(int k=1;k<N;k++)    {        if(!dp[i][j][k])    continue;        for(int t=k;j+t < N && t <= j+1;t++)            (dp[i+1][j+t][t] += dp[i][j][k]) %= mod;    }    int n,m,T;    scanf("%d",&T);    while(T-- && scanf("%d %d",&n,&m)){        ans = 0;        for(int k=1;k<=m;k++)            (ans += dp[n][m][k]) %= mod;        printf("%lld\n",ans);    }}

D Pairs

Description

Given N integers, count the number of pairs of integers whose sum isless than K. And we have M queries.

Input

The first behavior is an integer T (1 < = T < = 10), on behalf of the number of sets of data. Each group of data is the first line N, M (1< = n, m < = 100000), The next line will give N integers. a[i] (0<=a[i]<=100000).

The next M lines, each line contains the query K (1 <=K<=200000).

Output

For each query, output the number of pairs of integers whose sum isless than K.

分析

FFT裸题

代码

#include<bits/stdc++.h>using namespace std;const double PI = acos(-1.0);struct Complex{    double r,i;    Complex(double _r = 0.0,double _i = 0.0){        r = _r, i = _i;    }    Complex operator-(const Complex &b)const{        return Complex(r-b.r,i-b.i);    }    Complex operator+(const Complex &b)const{        return Complex(r+b.r,i+b.i);    }    Complex operator*(const Complex &b)const{        return Complex(r*b.r-i*b.i,r*b.i+i*b.r);    }};void rev(Complex y[],int len){    int i,j,k;    for(i=1,j=len/2;i<len-1;i++){        if(i<j) swap(y[i],y[j]);        k = len / 2;        while(j >= k){            j-=k;            k/=2;        }        if(j<k) j+=k;    }}void fft(Complex y[],int len,int DFT){    rev(y,len);    for(int h = 2; h <= len; h <<= 1){        Complex wn(cos(-DFT*2*PI/h),sin(-DFT*2*PI/h));        for(int j = 0;j < len;j+=h){            Complex w(1,0);            for(int k = j;k < j+h/2;k++){                Complex u = y[k];                Complex t = w*y[k+h/2];                y[k] = u+t;                y[k+h/2] = u-t;                w = w*wn;            }        }    }    if(DFT == -1)        for(int i = 0;i < len;i++)            y[i].r /= len;}const int maxn = 1<<18;int cnt[100010];Complex x[maxn];long long ans[200020];int main(){    int T,n,m,k;    scanf("%d",&T);    while(T--){        memset(cnt,0,sizeof(cnt));        scanf("%d %d",&n,&m);        for(int i=1,a;i<=n;i++)            scanf("%d",&a), cnt[a]++;        for(int i=0;i<maxn;i++){            if(i > 100000)  x[i].r = 0, x[i].i = 0;            else    x[i].r = cnt[i],    x[i].i = 0;        }        fft(x,maxn,1);        for(int i=0;i<maxn;i++)            x[i] = x[i] * x[i];        fft(x,maxn,-1);        ans[0] = x[0].r + 0.5;        for(int i=1;i<=200000;i++){            ans[i] = ans[i-1] + (long long)(x[i].r + 0.5);            if(i%2==0)  ans[i] -= cnt[i/2];        }        for(int i=0;i<=200000;i++)            ans[i] /= 2;        while(m--){            scanf("%d",&k);            printf("%lld\n",ans[k-1]);        }    }}



E 666

Description

CA loves “6” very much.

Now CA has a string S which consists of N digits. Now, she wonders that there are how many non-empty strings are substring of S and only contain number “6”

Input

First line contains T denoting the number of test cases. T test cases follow. Each test case contains a integer in the first line, denoting N, the length of string S. The second line is a string whose length is N.

1≤T≤10, 2≤N≤200000

Output

For each testcase, output answer.

分析

统计连续6的个数,该最长子串中全6子串个数为cnt*(cnt+1)/2;

代码

#include<bits/stdc++.h>using namespace std;char s[200020];int main(){    int T,n;    scanf("%d",&T);    while(T--){        scanf(" %d %s",&n,s);        long long ans = 0,cnt = 0;        for(int i=0;i<n;i++){            if(s[i] == '6') cnt++;            else if(cnt != 0){                ans += cnt*(cnt+1)/2;                cnt = 0;            }        }        if(cnt) ans += cnt*(cnt+1)/2;        printf("%lld\n",ans);    }}

F Fibonacci Again

Description

There are another kind of Fibonacci numbers: F(0) = 7, F(1) = 11,F(n) = (F(n-1) + F(n-2)) xor (n&1) (n>=2).

Input

Input consists of a sequence of lines, each containing an integer n.(0<=n < 1,000,000,000).

Output

Output F(n) mod1000000007.

分析

对于递推式问题,通常用矩阵快速幂解决。

构造矩阵
构造矩阵

代码

#include<bits/stdc++.h>using namespace std;const long long mod = 1000000007,maxn = 8,maxm = 8;long long init[8][8] = {{1,1,1,0,0,0,0,0},{1,0,0,0,0,0,0,0},{0,0,0,1,0,0,0,0},{0,0,0,0,1,0,0,0},{0,0,0,0,0,1,0,0},{0,0,0,0,0,0,1,0},{0,0,0,0,0,0,0,1},{0,0,1,0,0,0,0,0}};long long ori[8][1] = {{11},{7},{0},{-1},{0},{1},{0},{1}};struct Matrix {    int n,m;            //矩阵大小    long long a[maxn][maxn];    //矩阵内容    void clear() {      //清空矩阵        n = m = 0;        memset(a,0,sizeof(a));    }    Matrix operator*(const Matrix &b) const{        //矩阵乘法        Matrix tmp; tmp.clear();        tmp.n = n;  tmp.m = b.m;        for(int i=0;i<n;i++)        for(int j=0;j<b.m;j++)        for(int k=0;k<m;k++)            (tmp.a[i][j]+=a[i][k]*b.a[k][j]) %= mod;        return tmp;    }}A,ans;void pow_mod(Matrix A,int k) {    while(k >= 1) {        if(k&1) ans = ans * A;        k >>= 1;        A = A * A;    }}int main() {    int k;    while(scanf("%d",&k)!=EOF) {        if(k<2) {printf("%d\n",k?11:7);  continue;};        A.n = 8,    A.m = 8;        for(int i=0;i<8;i++)        for(int j=0;j<8;j++)            A.a[i][j] = init[i][j];        ans.clear();    //构造单位矩阵I        ans.n = 8,    ans.m = 8;        for(int i=0;i<8;i++)    ans.a[i][i] = 1;        pow_mod(A,k-1);        //ans矩阵为A^k的结果        A.m = 1;        for(int i=0;i<8;i++)            A.a[i][0] = ori[i][0];        ans = ans * A;        printf("%d\n",ans.a[0][0]);    }}

G Recurring Decimal

Description

As we all know, any scores are can be written in aninfinite recurring decimal or a finite decimal ,for example,1/7 can be writtenin 0.(142857).(recurring period is in the brackets).Now Give you a number x, could you tell me the length of non-recurring period and recurringperiod of 1/x

Input

There are multiple cases in the input.

In each case, there is a number x in a line(x is not greater than 2e9)

when x == 0 means end.

Output

For each test case, output two number a,b in a line separate with a space, mean the length of non-recurring period and recurring period.

分析

数学题好难。。。

引理1: 如果一个既约真分数a/b的分母b,既包含有质因数2和5,又含有2和5以外的质因数;

(1)这个分数所化成的小数是混循环小数

(2)它的小数部分中,不循环的位数等于分母里的因数2和5的指数中较大的一个数;

(3)循环节的最小位数,与b中2和5以外的质因数的积能整除999…9(t个9)时的最小个数t相同


x=2ktwo5kfivey(1)

y=pkii(2)

其中pi为非2、5的质数。

即length of non-recurring period is max{ktwo,kfive}

对于求循环节的长度:

​ 问题可以转换为求满足10t1(mod y)的最小t。

欧拉定理: 若a与n互质,则

aϕ(n)1(mod n)

其中,欧拉函数ϕ(n),表示小于或等于n的数中与n互质的数的数目。

此时ϕ(y)为t的一个可行解,但不一定是最小的。

故通过判断ϕ(y)的每个因子t,求满足10t1(mod y)的最小t。

代码

#include<bits/stdc++.h>using namespace std;long long phi(long long n){    long long ans = n;    for(long long i = 2;i*i <= n;i++){        if(n % i == 0){            ans -= ans/i;            while(n % i == 0)   n /= i;        }    }    if(n > 1)   ans -= ans/n;    return ans;}long long pow_mod(long long a,long long i,long long mod) {    long long ans = 1;    while(i >= 1) {        if(i&1) (ans *= a) %= mod;        i >>= 1;        (a *= a) %= mod;    }    return ans;}int main(){    int ans1 = 0,   ans2 = 0,   x;    while(scanf("%d",&x)!=EOF && x){        int two = 0,    five = 0;        for(;x%2==0;x/=2,two++);        for(;x%5==0;x/=5,five++);        ans1 = max(two,five),   ans2 = 0;        int euler = phi(x);        int tmp = (int)sqrt(x*1.0);        for(int i=1;i<=tmp;i++){            if(euler % i == 0){                if(pow_mod(10,i,x) == 1)    {ans2 = i;break;}                else if(pow_mod(10,euler/i,x) == 1) ans2 = euler/i;            }        }        printf("%d %d\n",ans1,ans2);    }}

H Blocks

Description

Now,you have infinite blocks,which size is 1 * 1 and 1 * 2,you want to fill a 1*n place.How many way to fill the place.

Input

There aremultiple cases in the input.

In each case, anumber n in a line, n <= 1e18,when n == 0 means end

Output

A number that how many way to fill a 1*n place,because the resultmay be huge,modulo 1e9+7

分析

简单思考即可得出,f[n]与f[n-1],f[n-2]相关,f[n]可由f[n-1] 添加一个1 * 1的blocks或由f[n-2]添加一个1 * 2的blocks,

即f[n] = f[n-1] + f[n-2],为斐波那契数列,可用矩阵快速幂解决。

当然也可考虑通过斐波那契数列的通项公式

f[n]=15[(1+52)n(152)n]

不知道精度能不能过。。。

代码

#include<bits/stdc++.h>using namespace std;const int mod = 1e9+7,maxn = 2,maxm = 2;struct Matrix {    int n,m;    long long a[maxn][maxn];    void clear() {          n = m = 0;        memset(a,0,sizeof(a));    }    Matrix operator*(const Matrix &b) const{        Matrix tmp; tmp.clear();        tmp.n = n;  tmp.m = b.m;        for(int i=0;i<n;i++)        for(int j=0;j<b.m;j++)        for(int k=0;k<m;k++)            (tmp.a[i][j]+=a[i][k]*b.a[k][j]) %= mod;        return tmp;    }}A,ans;void pow_mod(Matrix A,long long k) {    while(k >= 1) {        if(k&1) ans = ans * A;        k >>= 1;        A = A * A;    }}int main() {    long long n;    while(scanf("%lld",&n) && n) {        A.n = 2,    A.m = 2;        A.a[0][0] = A.a[0][1] = 1;        A.a[1][0] = 1,  A.a[1][1] = 0;        ans.clear();        ans.n = 2,    ans.m = 2;        for(int i=0;i<2;i++)    ans.a[i][i] = 1;        pow_mod(A,n-1);        A.m = 1;        ans = ans * A;        printf("%d\n",ans.a[0][0]);    }}

I Pairs Again

Description

Given N integers, count the number of pairs of integers whose difference is K.

Input

Input contains multiple test cases. For each test case , the first line contains N and K.

The second line contains N numbers of the set.

2<=N<=10^5

0

Output

An integer that tells the number of pairs of integers whose difference is K.

分析

考虑用STL的map加以解决。

用迭代器遍历map中的元素,若(it->first) & (it->first + k)均存在且大于0,则对答案贡献为两者出现次数的和。

HINT: 在map遍历中,若使用map[x] != 0的形式判断x是否存在,则默认会在map中插入一个x节点(此处可能导致TLE)

代码

#include<bits/stdc++.h>using namespace std;map<long long,int> mp;map<long long,int>::iterator it;int main(){    for(int n,k;scanf("%d %d",&n,&k)!=EOF;){        mp.clear();        for(int i=0,x;i<n;i++)            scanf("%d",&x), mp[x]++;        long long ans = 0;        for(it = mp.begin();it!=mp.end();it++){            long long tmp = it->first + k;            if(it->second && mp[tmp] != 0)                ans += (long long)it->second * mp[it->first + k];        }        printf("%lld\n",ans);    }}

J Odd number

Description

Given N integers, count the number of odd integers.

Input

Input contains multiple test cases. For each test case , the first line contains N.

The second line contains N numbers of the set. 2<=N<=10^5

Each integer will be greater than 0 and smaller than 2^31-1.

Output

For each test case, output a integer that tells the answer.

分析

统计有多少个奇数。

代码

#include<bits/stdc++.h>using namespace std;int main(){    for(int n,x,ans;scanf("%d",&n)!=EOF;){        ans = 0;        while(n--){            scanf("%d",&x);            if(x&1) ans++;        }        printf("%d\n",ans);    }}

K Candy

Description

Alex has prepared n different candies. Before he distributes these candies to the children Alex would like to consider all his options. If there are m children in the school find out the number of ways Chef can distribute these n candies to m children.

Since the number of ways to distribute cookies may be very large report the answer modulo 1e9+7.

Input

The first line of input consists of T, the number of test cases.

The next T lines consist of 2 integers each, n and m.1 <=T <= 10^5

1<=n,m<=1e9

Output

Print T lines with the answer for each case on a new line.

分析

mn, 快速幂。。。

代码

#include<bits/stdc++.h>using namespace std;long long pow_mod(long long a,long long i,long long mod) {    long long ans = 1;    while(i >= 1) {        if(i&1) (ans *= a) %= mod;        i >>= 1;        (a *= a) %= mod;    }    return ans;}int main(){    int T,n,m;    scanf("%d",&T);    while(T-- && scanf("%d %d",&n,&m)){        printf("%d\n",pow_mod(m,n,1e9+7));    }}

L Lucky Number

Description

Alex loves lucky numbers very much. Everybody knows that lucky numbers are positive integers whose decimal record contains only the luckydigits 6 and 8. For example, numbers 68, 688, 6 are lucky and 5, 18, 467 are not.

Alex loves long lucky numbers very much. He is interested in the minimum lucky number d that meets some condition. Let cnt(x) be the number of occurrences of number x in number d as a substring. For example, if d=868868, then cnt(6)=2, cnt(8) = 4, cnt(68) = 2, cnt(86) = 2. Petya wants the following condition to fulfil simultaneously: cnt(6) = a1, cnt(8) = a2, cnt(68) = a3, cnt(86) = a4. Alex is not interested in the occurrences of other numbers. Help him cope with this task.

Input

Input contains multiple testcases. For each test case , the single line contains four integers a1, a2, a3and a4 (1 ≤ a1, a2, a3, a4 ≤ 1000000).

Output

For each test case, output a single line printwithout leading zeroes the answer to the problem — the minimum lucky number d such, that cnt(6) =a1, cnt(8) = a2, cnt(68) = a3, cnt(86) = a4. If such number does not exist, print the single number “-1” (without the quotes).

分析

模拟题,要求满足cnt(6) = a1, cnt(8) = a2, cnt(68) = a3, cnt(86) = a4,且该数字最小。

显然,a3与a4最大相差为1。a1max(a3,a4)a2max(a3,a4)

对于a3 > a4,构造“6868…6868”形式,多余6插入第一个6之前,多余8插入最后一个8之后

对于a3 < a4,构造“8686…8686”形式,多余6插入第一个6之前,多余8插入最后一个8之后

对于a3 = a4,

​ 其中a1 = a2 & a2 = a3时,无解此处不证明,自己想

​ 对于a1 != a3,构造“6868..68686”形式,多余6插入第一个6之前,多余8插入最后一个8之后
​ 对a1 = a3情况,需特判。

代码

#include<bits/stdc++.h>using namespace std;int a1,a2,a3,a4;void print(int len,string s){    while(len-- > 0)  cout<<s;}bool formStr(){    if(a1 < max(a3,a4) || a2 < max(a3,a4) || abs(a3-a4) > 1)  return false;    if(a3 > a4){        print(a1-a3,"6");        print(a3,"68");        print(a2-a3,"8");    }else if(a3 < a4){        print(1,"8");        print(a1-a3-1,"6");        print(a3,"68");        print(a2-a3-1,"8");        print(1,"6");    }else{        if(a1 == a2 && a1 == a3)    return false;        if(a1 == a3){            print(1,"8");            print(a1-a3-1,"6");            print(a3,"68");            print(a2-a3-1,"8");        }else{            print(a1-a3-1,"6");            print(a3,"68");            print(a2-a3,"8");            print(1,"6");        }    }    printf("\n");    return true;}int main(){    while(scanf("%d %d %d %d",&a1,&a2,&a3,&a4)!=EOF)        if(!formStr())   printf("-1\n");}
0 0
原创粉丝点击