现在只会做8题。。。。ABCDEFGJ
题目在sdut 2877-2886
A. angry birds again and again
链接 http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2877
题目描述
输入
输出
示例输入
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
题目描述
输入
输出
示例输入
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
题目描述
输入
输出
示例输入
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
题目描述
输入
输出
示例输入
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
题目描述
输入
输出
示例输入
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
题目描述
输入
输出
示例输入
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
题目描述
and , S indicates
输入
输出
示例输入
7 10 35 5 10 15 5 20 10 35 5 10 15 5 20
示例输出
20
提示
题意:有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;
}