2014山东省第五届ACM省赛

现在只会做8题。。。。ABCDEFGJ

题目在sdut 2877-2886


A. angry birds again and again

链接 http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2877

题目描述

The problems called "Angry Birds" and "Angry Birds Again and Again" has been solved by many teams in the series of contest in 2011 Multi-University Training Contest.
 
This time we focus on the yellow bird called Chuck. Chuck can pick up speed and distance when tapped.
 
You can assume that before tapped, Chuck flies along the parabola. When tapped, it changes to fly along the tangent line. The Chuck starts at the coordinates (0, 0). Now you are given the coordinates of the pig (Px, 0), the x-coordinate of the tapping position (Tx) and the initial flying angle of Chuck (α).

∠AOx = α
Please calculate the area surrounded by Chuck’s path and the ground.(The area surrounded by the solid line O-Tapping position-Pig-O)

输入

The first line contains only one integer T (T is about 1000) indicates the number of test cases. For each case there are two integers, px tx, and a float number α.(0 < Tx ≤ Px ≤ 1000, 0 < α <  ) .

输出

One line for each case specifying the distance rounded to three digits.

示例输入

1
2 1 1.0

示例输出

0.692

题意:小鸟从(0,0)开始以α角飞出,轨迹是抛物线,到横坐标为Tx处开始沿切线方向飞,撞到(P,0)处的猪。求它飞行轨迹与x轴围的面积。

设抛物线方程 y = -Ax^2+Bx . 求导,根据两个斜率求出A和B,然后积分就好,最后再加上三角形的面积。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;

int t,p;
double af;
double A,B;

double fun(double x){
    return -A*x*x + B*x;
}
int main(){
    int casn;
    scanf("%d",&casn);
    while(casn--){
        scanf("%d%d%lf",&p,&t,&af);
        B = tan(af);
        int L = p-t;
        A = B*(L+t)/(2*L*t+t*t);
        double ans;
        ans = -A/3*pow(t,3) + B/2*pow(t,2);
        ans += (fun(t)*(p-t))/2;
        printf("%.3lf\n",ans);
    }
    return 0;
}
 


B.Circle

题目描述

You have been given a circle from 0 to n - 1. If you are currently at x, you will move to (x - 1) mod n or (x + 1) mod n with equal probability. Now we want to know the expected number of steps you need to reach x from 0.

输入

The first line contains one integer T — the number of test cases.
 
Each of the next T lines contains two integers n, x (0  ≤ x < n ≤ 1000) as we mention above.

输出

For each test case. Print a single float number — the expected number of steps you need to reach x from 0. The figure is accurate to 4 decimal places.

示例输入

3
3 2
5 4
10 5

示例输出

2.0000
4.0000
25.0000


题意:n个格子围成一圈,编号0~n-1,你一开始在x位置,每次等概率向左或向右走一步,问走到0位置的步数的期望是多少。

d[i]表示走到i位置的步数期望,则d[i] = d[i-1]*0.5 + d[i+1]*0.5 + 1,也就是 d[i] - d[i-1]*0.5 - d[i+1]*0.5 = 1,这样的方程共有n个,解线性方程组,最后x0就是答案。

直接用普通高斯消元模板会TLE,仔细一想会发现,每个方程都只有3个系数是非零的,也就是大部分系数都是0,根据这点加个剪枝就好了。


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

#define rep(i,f,t) for(int i = (f),_end = (t); i <= _end; ++i)
#define dep(i,f,t) for(int i = (f),_end = (t); i >= _end; --i)

const double eps = 1e-9;

typedef vector<double> Vec;
typedef vector<Vec> Mat;

bool equ(double a,double b){
    return fabs(a-b) < eps;
}

//<span style="color:#000000;">前<span style="font-family:Courier New;">n*n</span><span style="font-family:Courier 10 Pitch;">保存矩阵,</span><span style="font-family:Courier New;">n</span><span style="font-family:Courier 10 Pitch;">列保存</span><span style="font-family:Courier New;">b</span><span style="font-family:Courier 10 Pitch;">,返回结果也保存在</span><span style="font-family:Courier New;">n</span><span style="font-family:Courier 10 Pitch;">列中</span></span>
bool gauss(Mat &a,int n){
    rep(i,0,n-1){
        rep(j,i+1,n-1)
            if(fabs(a[j][i]) > fabs(a[i][i]))
                swap(a[j],a[i]);
        if(equ(a[i][i], 0))return false;
        if(!equ(a[i][i],1))  dep(k,n,i)a[i][k] /= a[i][i];

        rep(j,i+1,n-1)if(!equ(a[j][i],0)){ //非0才进入
            dep(k,n,i) a[j][k]-=a[i][k]*a[j][i];
        }
    }
    dep(i,n-1,0)rep(j,i+1,n-1)
        a[i][n] -= a[i][j]*a[j][n];
    return true;
}

const int maxn = 1005;
Mat a(maxn,Vec(maxn,0));
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,x;
        scanf("%d%d",&n,&x);
        rep(i,0,n-1)rep(j,0,n)a[i][j] = 0;
        rep(i,0,n-1){
            a[i][i] = 1;
            if(i != x){
                a[i][(i+1)%n] = -0.5;
                a[i][(i-1+n)%n] = -0.5;
                a[i][n] = 1;
            }
        }
        gauss(a,n);
        printf("%.4lf\n",a[0][n]);
    }
    return 0;
}



C.Colorful Cupcakes


题目描述

Beaver Bindu has N cupcakes. Each cupcake has one of three possible colors. In this problem we will represent the colors by uppercase letters \'A\', \'B\', and \'C\'. Two cupcakes of the same color are indistinguishable. You are given a String cupcakes consisting of exactly N characters. Each character in cupcakes gives the color of one of Bindu\'s cupcakes.
 
Bindu has N friends, sitting around a round table. She wants to give each friend one of the cupcakes. Moreover, she does not want to give cupcakes of the same color to any pair of friends who sit next to each other.
 
Let X be the number of ways in which she can hand out the cupcakes to her friends. As X can be very large, compute and return the value (X modulo 1, 000, 000, 007).

输入

The first line contains one integer T(1 ≤ T ≤ 60)—the number of test cases. Each of the next T lines contains one string. Each string will contain between 3 and 50 characters, inclusive. Each character in the string will be either \'A\', \'B\', or \'C\'.

输出

For each test case. Print a single number X — the number of ways in which she can hand out the cupcakes to her friends.
 

示例输入

3
ABAB
ABABA
ABABABABABABABABABABABABABABABABABABABABABABABABAB

示例输出

2
0
2


题意:有3种蛋糕,分别是ABC,共有n块,n个小盆友围一圈,求相邻小盆友不分到同一种蛋糕的方案数。

我这写的好复杂,d[i][a][b][j]表示第i个小盆友分到j类蛋糕,已分出a块A,b块B的方案。j用0,1,2分别表示A,B,C三类。

则由于最后一个与第1个也不能相同,所以还得枚举第一个分了哪种。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;
typedef long long int64;
const int mod = 1000000007;
int n,A,B,C;
char str[55];
int cnt[3];
int64 d[55][55][55][3];

int solve(int x){ //表示固定第一块蛋糕为x类的方案数。
    clr(d,0);
    if(x==0) d[1][1][0][0] = 1;
    else if(x == 1) d[1][0][1][1] = 1;
    else d[1][0][0][2] = 1;

    rep(i,2,n)rep(a,0,min(i,A))rep(b,0,min(B,i-a)){
        int c = i-a-b;
        if(c > C)continue;
        if( (a==0)+(b==0)+(c==0) >= 2)continue;  //abc出现两个以上的0为无效状态

        if(a && ((i!=2 && i!=n) || x!=0))d[i][a][b][0] = ( d[i][a][b][0] + d[i-1][a-1][b][1] + d[i-1][a-1][b][2] ) % mod;
        if(b && ((i!=2 && i!=n) || x!=1))d[i][a][b][1] = ( d[i][a][b][1] + d[i-1][a][b-1][0] + d[i-1][a][b-1][2] ) % mod;
        if(c && ((i!=2 && i!=n) || x!=2))d[i][a][b][2] = ( d[i][a][b][2] + d[i-1][a][b][0] + d[i-1][a][b][1] ) % mod;
    }
    return ( d[n][A][B][0] + d[n][A][B][1] + d[n][A][B][2] ) % mod;
}
int main(){
    int casn;
    scanf("%d",&casn);
    while(casn--){
        scanf("%s",str);
        n = strlen(str);
        A = cnt[0] = count(str,str+n,'A');
        B = cnt[1] = count(str,str+n,'B');
        C = cnt[2] = count(str,str+n,'C');
        int64 ans[3];clr(ans,0);
        rep(i,0,3)if(cnt[i])ans[i] = solve(i);
        ans[0] += ans[1]+ans[2];
        ans[0] %= mod;
        printf("%d\n",ans[0]);
    }
    return 0;
}
 

D.Devour Magic


题目描述

In Warcraft III, Destroyer is a large flying unit that must consume magic to sustain its mana. Breaking free of the obsidian stone that holds them, these monstrous creatures roar into battle, swallowing magic to feed their insatiable hunger as they move between battles and rain destruction down upon their foes. Has Spell Immunity. Attacks land and air units.
The core skill of the Destroyer is so called Devour Magic, it takes all mana from all units in a area and gives it to the Destroyer.
 
Now to simplify the problem, assume you have n units in a line, all unit start with 0 mana and can increase to infinity maximum mana. All unit except the Destroyer have mana regeneration 1 in per unit time.
 
The Destroyer have m instructions t l r, it means, in time t, the Destroyer use Devour Magic on unit from l to r. We give you all m instructions in time order, count how many mana the Destroyer have devour altogether.

输入

The first line contains one integer T, indicating the test case. For each test case, the first contains two integer n, m(1 ≤ n, m ≤ 10^5). The the next m line each line contains a instruction t l r.(1 ≤ t ≤ 10^5, 1 ≤ l ≤ r ≤ n)

输出

For each test case, output the conrespornding result.

示例输入

1
10 5
1 1 10
2 3 10
3 5 10
4 7 10
5 9 10

示例输出

30


题意:一行n个格,初始值都为0,每秒钟所有格子的值都会+1。有个人会在某些时候删除某个区间的值,即将该区间清零。给他操作的序列,问他删除的值的和是多少。

很裸的一道线段树。。。。入门经典上的线段树就是讲的这两种操作。。。。

求出与上一次操作的时间间隔,给整段区间加上这个数,要删除时先记录下删除的区间和,然后将这个区间清0。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;
typedef long long int64;

#define CHILDREN int lc = node<<1, rc = node<<1|1;
#define MID int mid = L + ((R-L)>>1);

const int maxn = 100000+5;
struct Node{
    int64 sumv,setv,addv;
};
struct SGT{
    Node T[maxn<<2];
    void init(){ T[1].setv = 0;T[1].addv = 0;}
    int op;

    void pushDown(int node){
        CHILDREN;
        if(T[node].setv >= 0){
            T[lc].setv = T[rc].setv = T[node].setv;
            T[lc].addv = T[rc].addv = 0;
            T[node].setv = -1;
        }
        if(T[node].addv){
            T[lc].addv += T[node].addv;
            T[rc].addv += T[node].addv;
            T[node].addv = 0;
        }
    }
    void maintain(int node,int L,int R){
        if(T[node].setv >= 0){
            T[node].sumv = T[node].setv * (R-L+1);
        } else if(L != R){
            CHILDREN;
            T[node].sumv = T[lc].sumv + T[rc].sumv;
        }

        if(T[node].addv){
            T[node].sumv += T[node].addv * (R-L+1);
        }

        if(L == R){
            T[node].setv = -1;
            T[node].addv = 0;
        }
    }
    int64 query(int from,int to,int node,int L,int R){
        if(from <= L && R <= to){
            return T[node].sumv;
        }else{
            MID;CHILDREN;
            pushDown(node);
            maintain(lc,L,mid);
            maintain(rc,mid+1,R);
            int64 ans = 0;
            if(from <= mid) ans += query(from,to,lc,L,mid);
            if(mid < to) ans += query(from,to,rc,mid+1,R);
            return ans;
        }
    }
    void update(int from,int to,int64 val,int node,int L,int R){
        if(from <= L && R <= to){
            if(op == 1){
                T[node].addv += val;
            }else{
                T[node].setv = val;
                T[node].addv = 0;
            }
        }else{
            MID;CHILDREN;
            pushDown(node);
            if(from <= mid) update(from,to,val,lc,L,mid);
            else maintain(lc,L,mid);
            if(mid < to) update(from,to,val,rc,mid+1,R);
            else maintain(rc,mid+1,R);
        }
        maintain(node,L,R);
    }
}tree;

int main(){
    int casn;
    scanf("%d",&casn);
    while(casn--){
        int n,m;
        scanf("%d%d",&n,&m);
        tree.init();
        int lt = 0;
        int64 ans = 0;
        while(m--){
            int t,l,r;
            scanf("%d%d%d",&t,&l,&r);
            int ad = t - lt;
            lt = t;
            if(ad){
                tree.op = 1;
                tree.update(1,n,ad,1,1,n);
            }
            ans += tree.query(l,r,1,1,n);
            tree.op = 2;
            tree.update(l,r,0,1,1,n);
        }
        printf("%lld\n",ans);
    }
    return 0;
}


E.Factorial

水题,求10以内的阶乘。


F.Full Binary Tree


题目描述

In computer science, a binary tree is a tree data structure in which each node has at most two children. Consider an infinite full binary tree (each node has two children except the leaf nodes) defined as follows. For a node labelled v its left child will be labelled 2 * v and its right child will be labelled 2 * v + 1. The root is labelled as 1.
 
You are given n queries of the form i, j. For each query, you have to print the length of the shortest path between node labelled i and node labelled j.
 

输入

First line contains n(1 ≤ n ≤ 10^5), the number of queries. Each query consists of two space separated integers i and j(1 ≤ i, j ≤ 10^9) in one line.
 

输出

For each query, print the required answer in one line.
 

示例输入

5
1 2
2 3
4 3
1024 2048
3214567 9998877

示例输出

1
2
3
1
44


给二叉树的两个结点标号i和j(标号从1开始),求它们间路径的长度。

当i!=j时直接将大的一个除以2,不断循环,每次答案+1。

初始时两点深度可能不等,将深度大的不断减小,当两者深度相等时,若i==j则可输出答案。否则继续循环下去,它们的深度差为0或1,总会在某个时候i==j。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;
typedef long long int64;

int solve(int a,int b){
    int ans = 0;
    while(a != b){
        if(a > b)a >>= 1;
        else b >>= 1;
        ++ans;
    }
    return ans;
}

int main(){
    int casn;
    scanf("%d",&casn);
    while(casn--){
        int a,b;
        scanf("%d%d",&a,&b);
        int ans = solve(a,b);
        printf("%d\n",ans);
    }
    return 0;
}
 


G.Hearthstone II


题目描述

The new season has begun, you have n competitions and m well prepared decks during the new season. Each competition you could use any deck you want, but each of the decks must be used at least once. Now you wonder how many ways are there to plan the season — to decide for each competition which deck you are going to used. The number can be very huge, mod it with 10^9 + 7.
 

输入

The input file contains several test cases, one line for each case contains two integer numbers n and m (1 ≤ m ≤ n ≤ 100).
 

输出

One line for each case, output one number — the number of ways.

示例输入

3 2
100 25

示例输出

6
354076161


题意:n次比赛,有m个场地,求每个场地至少用一次的方案数。

d[i][j]表示前i次比赛用了j个场地的方案数。

d[i][j] = d[i-1][j] * j + d[i-1][j-1] * (m-j+1)


#include<iostream>
#include<cassert>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;
typedef long long int64;

const int mod = 1000000007;
const int maxn = 110;
int d[maxn][maxn];

int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        clr(d,0);
        d[0][0] = 1;
        rep(i,1,n)rep(j,1,min(m,i)){
            d[i][j] = ((int64)d[i-1][j]*j%mod + (int64)d[i-1][j-1]*(m-j+1)%mod ) % mod;
        }
        printf("%d\n",d[n][m]);
    }
    return 0;
}
 


J.Weighted Median

题目描述

For n elements x1, x2, ..., xn with positive integer weights w1, w2, ..., wn. The weighted median is the element xk satisfying
 and   , S indicates 
Can you compute the weighted median in O(n) worst-case?
 

输入

There are several test cases. For each case, the first line contains one integer n(1 ≤  n ≤ 10^7) — the number of elements in the sequence. The following line contains n integer numbers xi (0 ≤ xi ≤ 10^9). The last line contains n integer numbers wi (0 < wi < 10^9).
 

输出

One line for each case, print a single integer number— the weighted median of the sequence.
 

示例输入

7
10 35 5 10 15 5 20
10 35 5 10 15 5 20

示例输出

20

提示

The S which indicates the sum of all weights may be exceed a 32-bit integer. If S is 5,  equals 2.5.

题意:有n个数x1...n,每个数对应一个权值w1..n。求满足上面两个式子的xk。

S/2可能不是整数,我将所有的w都放大一倍,性质不变。

输入的时候顺便把S计算出来,然后按x排序,接着从左往右累加w,当某个时候sum>=S/2时,扫到的那个x就是答案。


x已是有序,假设扫到k位置时sum>=S/2,则1~k-1位置的w的和时小于S/2的,而大于k+1~n位置的w的和就是S-sum,自然是<=S/2。


#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;
typedef long long int64;

const int maxn = 10000000+1;
int a[maxn];
typedef map<int,int64> Map;
Map m;

int main(){
    int n;
    while(scanf("%d",&n) == 1){
        m.clear();
        rep(i,1,n) scanf("%d",a+i);
        int64 sum = 0;
        rep(i,1,n){
            int64 x;
            scanf("%lld",&x);
            sum += x<<1;
            m[a[i]] += x<<1;
        }
        sum >>= 1;

        int64 s = 0;
        Map::iterator it = m.begin();
        int ans = (m.begin())->first;
        for(; it != m.end(); ++it){
            s += it->second;
            if(s >= sum){
                ans  = it->first;
                break;
            }
        }
        
        printf("%d\n",ans);
    }
    return 0;
}
 









  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值