A.angry_birds_again_and_again
简单积分:
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2877
给定曲线,给定一个点,求从曲线上某点到x轴上某点直线恰为曲线切线和曲线围成的面积。
水题,求积分做就好了,但是开始还错了,回车竟然判成WR而不是PR,第一题就卡,醉了。。。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define MAX 100005 #define INF 0x3f3f3f3f #define LL long long #define pii pair<string,int> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) using namespace std; int main() { double a,b,du; double T,P; int xx,yy; int n; rd(n); while(n--) { rd2(xx,yy); T=yy,P=xx; scanf("%lf",&du); b=tan(du); a=b*P/(T*T-2*T*P); double y0=a*T*T+b*T; double area = 1/3.0*a*T*T*T+1/2.0*b*T*T + 1/2.0*(P-T)*y0; //cout<<a<<' ' <<y0<<endl; printf("%.3f\n",area); } return 0; }
B.Circle
高斯消元
n个数围成一个圈,编号0~n-1,从一个数到其上一个和下一个的数的概率相同(即都是0.5)。给出n,求从0出发到达一个数x所需要的步数的数学期望。
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2878
某大神从小数找到一个规律。。。
d[0]=0,d[1]=n-1,d[2]=(n-1)+(n-3),d[3]=(n-1)+(n-3)+(n-5),……。
这样就可以递推了。
但是这道题正解好像是高斯消元,但是在省赛这种稍微水点的,尤其是感觉和数学有关的用递推的方式试试,可能列举几个数就能找出规律,这种方法看起来比较白痴,但是作用有的时候还是比较大的...谨记。。。
高斯消元的方法之后补上。。。
看完这简短的代码瞬间感觉递推找规律很吊很吊有木有。。。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define MAX 100005 #define INF 0x3f3f3f3f #define LL long long #define pii pair<string,int> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) using namespace std; int main() { int T,x,n; rd(T); int dp[1005]; dp[0]=0; while(T--) { rd2(n,x); for(int i=1,j=1;i<=x;i++,j+=2) dp[i]=dp[i-1]+(n-j); printf("%.4f\n",(float)dp[x]); } return 0; }
C.Colorful Cupcakes
dp问题
题目网址:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2879
给出ABC三种颜色的个数,求相邻颜色不相同,首尾颜色不相同的串的个数。
思路:
开始的时候感觉就是个搜索,但是一想简单搜索肯定超时,dp的话也没找出递推公式,竟让把记忆化搜索给忘了,悲哀。。。
dp[i][a][b][k]表示前i个位置A有a个B有b个,当前位置颜色是k的个数。
假设当前颜色是红色,也就是0(自己定)
dp[i][a][b][k]=∑dp[i−1][a−1][b][ii], ii = 1,2,3. ii != k,ii是上一个位置的颜色,不能和k相同。
从后往前搜索
#include <stack> #include <cstdio> #include <list> #include <set> #include <iostream> #include <string> #include <vector> #include <queue> #include <functional> #include <cstring> #include <algorithm> #include <cctype> #include <string> #include <map> #include <cmath> using namespace std; const int MAXN = 50 + 3; const int MOD = 1e9 + 7; char str[100]; int cnt[3]; int dp[MAXN][MAXN][MAXN][3]; int lastColor ; ///记忆化搜索 也就是算法设计中所说的备忘录方法 int DFS(int pre, int a, int b, int k)///前pre位有a个A色b个绿色,此位是k颜色的个数 { if (dp[pre][a][b][k] != -1) return dp[pre][a][b][k]; if (a < 0 || b < 0 || pre-a-b < 0) return 0; if (pre == 1 && k == lastColor) return 0; ///如果第一位和最后一位相同,0种情况 if (pre == 1) return dp[pre][a][b][k] = ((a && k == 0) || (b && k == 1) || (pre-a-b && k == 2)); ///有可能出现第一位本来已经没多余的某种颜色了,却能走到这一步。排除 ///因为枚举前一位是什么颜色的时候并没考虑那种颜色还有没有剩余 int ans = 0; for (int ii = 0; ii < 3; ii++) ///前一位是什么颜色 { if (k == ii) continue; if (k == 0) ans = (ans + DFS(pre-1, a-1, b, ii)) % MOD; if (k == 1) ans = (ans + DFS(pre-1, a, b-1, ii)) % MOD; if (k == 2) ans = (ans + DFS(pre-1, a, b, ii)) % MOD; } return dp[pre][a][b][k] = ans; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%s", str); memset(dp,-1,sizeof(dp)); memset(cnt,0,sizeof(cnt)); int len = strlen(str); for (int i = 0; i < len; i++) cnt[str[i]-'A']++; int ans = 0; for (int i = 0; i < 3; i++) ///最后一位是什么颜色 { memset(dp,-1,sizeof(dp)); lastColor=i; ans = (ans + DFS(len, cnt[0], cnt[1], i)) % MOD; for(int i=1;i<=len;i++) for(int j=1;j<=len;j++) for(int x=1;x+j<=len;x++) for(int k=0;k<3;k++) if(dp[i][j][x][k]!=-1) cout<<"dp["<<i<<"]["<<j<<"]["<<x<<"]["<<k<<"]"<<dp[i][j][x][k]<<endl; } printf("%d\n", ans); } return 0; }
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define MAX 100005 #define INF 0x3f3f3f3f #define LL long long #define pii pair<string,int> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) const int dir[][2] = { {-1, 0}, {0, -1}, { 1, 0 }, { 0, 1 } }; using namespace std; const int MAXN = 50 + 3; const int MOD = 1e9 + 7; char str[100]; int cnt[3]; int dp[MAXN][MAXN][MAXN][3]; int firstColor,len; ///记忆化搜索 也就是算法设计中所说的备忘录方法 int DFS(int pre, int a, int b, int k)///前pre位有a个A色 b个B色,k是本次要搜索的颜色标志 { if ((k==0 && a+1 > cnt[0]) || (k==1 && b+1 > cnt[1]) || (k==2 && pre-a-b > cnt[2])) return 0; if (dp[pre][a][b][k] != -1) return dp[pre][a][b][k]; if (pre == len && k == firstColor) return 0; ///如果第一位和最后一位相同,0种情况 if (pre == len) return ((a+1<=cnt[0] && k == 0) || (b+1<=cnt[1] && k == 1) || (pre-a-b <= cnt[2] && k == 2)); ///有可能出现第一位本来已经没多余的某种颜色了,却能走到这一步。排除 ///因为枚举前一位是什么颜色的时候并没考虑那种颜色还有没有剩余 int ans = 0; for (int ii = 0; ii < 3; ii++) ///前一位是什么颜色 { if (k == ii) continue; if (k == 0) ans = (ans + DFS(pre+1, a+1, b, ii)) % MOD; if (k == 1) ans = (ans + DFS(pre+1, a, b+1, ii)) % MOD; if (k == 2) ans = (ans + DFS(pre+1, a, b, ii)) % MOD; } return dp[pre][a][b][k] = ans; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%s", str); memset(dp,-1,sizeof(dp)); memset(cnt,0,sizeof(cnt)); len = strlen(str); for (int i = 0; i < len; i++) cnt[str[i]-'A']++; int ans = 0; for (int i = 0; i < 3; i++) ///最后一位是什么颜色 { memset(dp,-1,sizeof(dp)); firstColor=i; ans = (ans + DFS(1, 0, 0, i)) % MOD; } printf("%d\n", ans); } return 0; }
n个单位,每个单位每秒增加1法力,在某些时间取走一些区间的法力值(取走之后该区间所有单位的法力变为0),求取得的所有法力值。
就是在原来的基础上增加了清零的操作,不过这个清零(实际代码中也可以置为任意值)的操作通过flag标志和一个sset变量来保存下要置的数,其他操作和正常pushdown一样,每次在输入时记录上一次更新的时间last,这一次直接t-last就好了。。。
之前的一个超时代码也先粘在这里吧,(标记的可能多搜了!!!),但是提交AC的代码和自己的思路是一模一样的,具体现在也不知道问题出在哪里
超时代码:
///线段树区间更新 #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<vector> #include<queue> #include<stack> #include<iomanip> #include<string> #include<climits> #include<cmath> #define INF 0x3f3f3f3f #define MAX 1100000 #define LL long long using namespace std; LL n,m; LL coun=0; int xx; struct Tree { LL l,r; LL sum,add; }; Tree tree[MAX*8]; void pushup(LL x) ///更新父节点 { tree[x].sum=tree[ x<<1 ].sum+tree[ (x<<1)+1 ].sum; } void pushdown(LL x) ///用于更新add数组 { if(x>xx){ tree[x].sum = 0; return ; } LL tmp = x<<1 ; if(tree[x].add == -INF){ // cout<<x<<"----------------------"<<endl; tree[tmp].add = -INF ; ///由子节点通过增加 tree[tmp+1].add = -INF; tree[tmp].sum = 0; tree[tmp+1].sum = 0; tree[x].add=0; tree[x].sum=0; return ; } if( tmp > xx ) return ; if(tree[tmp].add == -INF ) pushdown(tmp); if(tree[tmp+1].add == -INF) pushdown(tmp+1); tree[tmp].add += tree[x].add; ///由子节点通过增加 tree[tmp].sum += tree[x].add*(tree[tmp].r-tree[tmp].l+1); tree[tmp+1].add += tree[x].add; tree[tmp+1].sum += tree[x].add*(tree[tmp+1].r-tree[tmp+1].l+1); if(tmp>xx) cout<<tmp<<" "<<tree[tmp].add<<" "<<tree[tmp].add<<" "<<tree[tmp].l<<" "<<tree[tmp].r<<endl; tree[x].add=0; } void build(int l,int r,int x) { tree[x].l=l , tree[x].r=r , tree[x].add=0; if(l==r) { tree[x].sum = 0; ///子节点初始化 tree[x].add = 0; return ; } int tmp=x<<1; int mid=(l+r)>>1; build(l,mid,tmp); build(mid+1,r,tmp+1); pushup(x); ///建立时需根据子节点更细父亲节点 } void update(LL l,LL r,LL c,LL x) ///分别表示区间的左 , 右 , 增加的值 ,当前父亲节点 { if(r<tree[x].l||l>tree[x].r||x>xx) return ; if(l<=tree[x].l&&r>=tree[x].r) ///该区间为需要更新区间的子区间 { // cout<<"************\n"; if(c==-INF){ tree[x].add = -INF; tree[x].sum = 0; return ; } if(x>xx) return ; if(tree[x].add == -INF ) pushdown(x); tree[x].add += c ; tree[x].sum += c*(tree[x].r-tree[x].l+1); ///区间长度*要增加的数值 return ; } ///如果比当前的范围还小,就通过该节点向下更新下面的节点 if(tree[x].add ) pushdown(x); ///更新从上向下更新add LL tmp=x<<1; if(tmp>xx){ pushup(x); return ; } update(l,r,c,tmp); update(l,r,c,tmp+1); } LL query(LL l,LL r,LL x) { ///if(r<tree[x].l||l>tree[x].r) return -INF;//要更新的区间不在该区间上(输入有误) if(l<=tree[x].l&&r>=tree[x].r) ///要计算的区间包括了该区间 { return tree[x].sum; } if( tree[x].add&&tree[x].add!=-INF ) pushdown(x); ///如果add不为零,对查询可能用到的add更新 LL tmp=x<<1; if(tmp>xx) return 0; LL mid=(tree[x].l+tree[x].r)>>1; if(r<=mid) return query(l,r,tmp); else if(l>mid) return query(l,r,tmp+1); else return query(l,mid,tmp)+query(mid+1,r,tmp+1); } int main() { int xxx; scanf("%d",&xxx); while(xxx--) { scanf("%I64d%I64d",&n,&m); xx=4*n; coun=0; build(1,n,1); LL last=0; while(m--) { LL l,r,time; scanf("%I64d%I64d%I64d",&time,&l,&r); update(1,n,time-last,1); /* cout<<"加"<<time-last<<endl; for(int i=1;i<=60;i++) cout<<i<<":"<<tree[i].add<<' '<<tree[i].sum<<" "; cout<<endl;*/ last = time ; coun+=query(l,r,1); update(l,r,-INF,1); /* for(int i=1;i<=60;i++) cout<<i<<":"<<tree[i].add<<' '<<tree[i].sum<<" "; cout<<endl;*/ } printf("%I64d\n",coun); } return 0; } /************************************** Problem id : SDUT OJ 2880 User name : 张士卫 Result : Time Limit Exceeded Take Memory : 0K Take Time : 2010MS Submit Time : 2016-04-02 09:36:52 **************************************/
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define L(root) ((root)<<1) #define R(root) (((root)<<1)|1) const int MAXN=1e5+10;// int numbers[MAXN];//初始值 struct node{ int left,right;/// long long sum; int add;///区间增加值 int sset; ///区间里的数设为v bool flag;///标记是否设置为v int mid(){ return ((right+left)>>1); } }tree[MAXN*4];//4倍空间 void pushUp(int root){ tree[root].sum=tree[L(root)].sum+tree[R(root)].sum; } void pushDown(int root){ int L=L(root),R=R(root); if(tree[root].flag){ tree[L].add=tree[R].add=0; tree[L].sset=tree[R].sset=tree[root].sset; tree[L].flag=tree[R].flag=true; tree[L].sum=tree[root].sset*(tree[L].right-tree[L].left+1); tree[R].sum=tree[root].sset*(tree[R].right-tree[R].left+1); tree[root].flag=false; } if(tree[root].add){ ///正常pushdown tree[L].add+=tree[root].add; tree[R].add+=tree[root].add; tree[L].sum+=tree[root].add*(tree[L].right-tree[L].left+1); tree[R].sum+=tree[root].add*(tree[R].right-tree[R].left+1); tree[root].add=0; } } void build(int root,int left,int right){ tree[root].left=left; tree[root].right=right; tree[root].add=0; tree[root].flag=false; if(left==right){ tree[root].sum=numbers[left]; return; } int mid=tree[root].mid(); build(L(root),left,mid); build(R(root),mid+1,right); pushUp(root); } long long query(int root,int left,int right){ if(tree[root].left==left&&tree[root].right==right) return tree[root].sum; pushDown(root); int mid=tree[root].mid(); if(right<=mid) return query(L(root),left,right); else if(left>mid) return query(R(root),left,right); else return query(L(root),left,mid)+query(R(root),mid+1,right); } void update(int root,int left,int right,int add){ if(tree[root].left==left&&tree[root].right==right){ tree[root].add+=add; tree[root].sum+=add*(right-left+1); return; } pushDown(root); int mid=tree[root].mid(),L=L(root),R = R(root); if(right<=mid) update(L,left,right,add); else if(left>mid) update(R,left,right,add); else{ update(L,left,mid,add); update(R,mid+1,right,add); } pushUp(root); } void setf(int root,int left,int right,int sset){ if(tree[root].left==left&&tree[root].right==right){ tree[root].add=0; tree[root].sum=sset*(right-left+1); tree[root].sset=sset; tree[root].flag=true; return; } pushDown(root); int mid=tree[root].mid(),L=L(root),R = R(root); if(right<=mid) setf(L,left,right,sset); else if(left>mid) setf(R,left,right,sset); else{ setf(L,left,mid,sset); setf(R,mid+1,right,sset); } pushUp(root); } int main(){ memset(numbers,0,sizeof(numbers)); int T; int n,m; int t,l,r; int i; int lastTime; long long sum; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); build(1,1,n); lastTime=0; sum=0; for(i=0;i<m;++i){ scanf("%d%d%d",&t,&l,&r); update(1,1,n,t-lastTime); sum+=query(1,l,r); setf(1,l,r,0);//l到r区间设为0 lastTime=t; } printf("%lld\n",sum); } return 0; }
E.Factorial
水题,求阶乘
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define MAX 100005 #define INF 0x3f3f3f3f #define LL long long #define pii pair<string,int> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) const int dir[][2] = { {-1, 0}, {0, -1}, { 1, 0 }, { 0, 1 } }; using namespace std; int main(){ int n,x; rd(n); while(n--){ rd(x); int sum=1; for(int i=1;i<=x;i++) sum*=i; printf("%d\n",sum); } return 0; }
在满二叉树中求两个节点的最近距离
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define MAX 100005 #define INF 0x3f3f3f3f #define LL long long #define pii pair<string,int> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) const int dir[][2] = { {-1, 0}, {0, -1}, { 1, 0 }, { 0, 1 } }; using namespace std; int main(){ int n,x,y; rd(n); while(n--){ rd2(x,y); int step=0; while(x!=y){ x>y?x/=2:y/=2; step++; } printf("%d\n",step); } return 0; }
n场比赛,m个场地,m<=n,1场比赛只能选择1个场地,要求每个场地必须使用过一次,求所有的方案数。
dp[i][j]表示:前i场比赛用了j个场地的情况数
dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1]*(m-j+1);
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MOD=1e9+7; int main(){ int n,m; long long dp[105][105];//dp[i][j]表示:前i场比赛用了j个场地的情况数 int i,j; while(~scanf("%d%d",&n,&m)){ memset(dp,0,sizeof(dp)); for(i=1;i<=n;++i) //j=1;前i场比赛用了1个场地,初始化为m dp[i][1]=m; for(i=2;i<=n;++i){ for(j=2;j<=i&&j<=m;++j){ dp[i][j]=((dp[i-1][j]*j)%MOD+(dp[i-1][j-1]*(m-j+1))%MOD)%MOD; } } printf("%lld\n",dp[n][m]); } return 0; }
H.Painting Cottages
I.Tree
J.Weighted Median
简单排序求和
不过这里有个处理0.5这样的数小技巧,先乘2,之后按照整数操作就行了。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define MAX 10000005 #define INF 0x3f3f3f3f #define LL long long #define pii pair<string,int> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) const int dir[][2] = { {-1, 0}, {0, -1}, { 1, 0 }, { 0, 1 } }; using namespace std; struct T{ int x; int w; }arr[MAX]; bool cmp(T a,T b){ return a.x<b.x; } int main(){ int n; LL sum,temp; int s; while(~rd(n)){ sum=0; temp=0; for(int i=0;i<n;i++) rd(arr[i].x); for(int i=0;i<n;i++) rd(arr[i].w); for(int i=0;i<n;i++) sum+=arr[i].w,arr[i].w=arr[i].w<<1; sort(arr,arr+n,cmp); s=arr[0].x; for(int i=0;i<n,temp<sum;s = arr[i].x,i++) temp+=arr[i].w; printf("%d\n",s); } return 0; }
Factorial |
Tree |