队内周六日常训练,我迟到了半个小时,然后两个dalao开始疯狂过题,这比赛是很多场现场赛组合来的,大概都是铜牌、铁牌,少部分银牌题。 比较适合我们队伍的情况。
A
似乎是二分图匹配? 简单的? 熊神交了几发就过了。
B
题意很简单:给a , b 求x,y 满足 x+y = a 且 lcm(x,y) = b
高中数学题
哼! 不是常说
模拟只会猜题意,贪心只能过样例。图论只会套模板,数论只会gcd
这下好了,出gcd了,你看还不是不会!
从x,y下手。我们设 gcd(x,y) = c
所以 x = i*c , y = j*c (i,j互质)
于是有:
lcm(x,y) = c*i*j = b
ic + jc = a = c*(i+j)
因为 i j 互质 i*j 的因数只有i和j 和1 和自己
所以 gcd(i+j , i*j) = gcd(i,i*j) 或者gcd(j,i*j);
假设 gcd(i,i*j)=x(x!=1)
则有:
i=ax
i*j=bx => j=(a-b)x 且可知a>b 所以 j=cx ,所以gcd(i,j)!=1 ,与题设矛盾
所以 gcd(i+j , i*j) =1 所以 gcd ( a,b ) = c
所以 i + j = a/c 且 i*j = b/c
然后就是解二元一次方程组。。。所以只需解出最小的i即可
C
给一个x 可以分成任意段:x1+x2+x3….,必须满足:
1.任何两段都不相同
2.求x1*x2*x3最大值
算了,不强行分析了,数论不是gcd,超出我的能力范围了。
D
点分治,熊神补了,先不看了
E
盒子里面有k个黑球,1个红球,谁先取出红球谁就胜利,问先手会有优势吗?
一开始没想好,以为后手会有优势,sb了一下。
k=1 一黑一红 先手既无优势也无劣势,55k
k=2 两黑一红,先手取1/3赢 即使没取到 轮到后手时 也是55k ,所以先手有优势。
k=3 三黑一红
000X
先手: 1/4 赢 3/4取不到
后手: 必须建立在先手取不到的情况: P(赢)=3/4 * 1/3 =1/4
然后55k。 所以 先手既无优势也无劣势,55k
k=4 0000X 先手取完一个之后,情况和k=3相同,所以先手肯定有优势
往后推 同理
F
貌似是个挺简单的计算几何,拆成三角形计算就可以了。 s=a*b*sinx*1/2?
G
化成二进制,然后再换成八进制,4位->1位
H
题意:一条路上有n条河,每条河有起点和终点,河里面会 随机在任何位置出现一条船,并且船的速度恒等于V,但是方向向左向右是随机的,走路的速度=1,求从A 走到B 的期望时间。
对单独一条河,过河的期望= 当船在河中心 的t(v向左)+t(v向右),这个怎么证明呢,我只能说根据题目条件可得= =,然后我们把所有河长度加起来当成一条河就可以了。
I
下载东西,一大堆规则,其实下载的总量是固定的,总速度是固定的,除一下就是答案。
J
HDU 3236
有很多物品,每个物品有体积,价值,属性(有些必须买,有些不必须)
给两个背包(v1,v2),跑0-1背包, 以及可以免费选任何一个物品。
求最大价值。
首先我们把物品分为必须和非必须
然后跑两遍0-1 背包,根本不需要记录我们选择了哪些物品
但必须记录我们选择完必须品之后的状态 dp[i][j] 。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
int dp[505][55][2];
//dp[i][j]代表使用的容量是i和j的最大价值, 再开一维表示免费的机会即可
struct node{
int v,w;
bool operator <(const node &b)const{
return v>b.v;
}
};
priority_queueq;
int main(){
int V1,V2,i,j,a,b,c,k,n,ans,cas,sum,pre,sign;
cas=1;
while(~scanf("%d%d%d",&V1,&V2,&n)&&(V1||V2||n)){
vector G[2];
memset(dp,-1,sizeof(dp));
for(i=0;iscanf("%d%d%d",&a,&b,&c); // 分别是 体积和价值,是否必须
G[c].push_back((node){a,b});
}
sum=dp[0][0][0]=0;
for(i=0;i1].size();i++){
pre=sum;
sum+=G[1][i].w;
for(j=V1;j>=0;j--){ // 第一个背包和第二个背包都必须扫
for(k=V2;k>=0;k--){
if(dp[j][k][0]==pre) //如果没用免费机会时,最大价值=pre
dp[j][k][1]=sum; //则用了免费会变成 这样
if(j>=G[1][i].v){
if(dp[j-G[1][i].v][k][1]==pre)
dp[j][k][1]=sum;
if(dp[j-G[1][i].v][k][0]==pre)
dp[j][k][0]=sum;
}
if(k>=G[1][i].v){
if(dp[j][k-G[1][i].v][1]==pre)
dp[j][k][1]=sum;
if(dp[j][k-G[1][i].v][0]==pre)
dp[j][k][0]=sum;
}
}
}
}
sign=0;
for(i=0;i<=V1;i++)
for(j=0;j<=V2;j++)
for(k=0;k<=1;k++){
if(dp[i][j][k]!=sum) //检测是否能把必需品装下,并且我们知道剩下的状态是怎样
dp[i][j][k]=-1;
else
sign=1; //我们保存了使用i,j空间装满所有必需品的状态
}
if(!sign){
printf("Case %d: -1\n\n",cas++);
continue;
} //
for(i=0;i0].size();i++){
for(j=V1;j>=0;j--){
for(k=V2;k>=0;k--){
if(dp[j][k][0]!=-1) //要放在最前面,避免了重复装入
dp[j][k][1]=max(dp[j][k][1],dp[j][k][0]+G[0][i].w);
// 必须满足!=-1 即:把必需品装完
if(j>=G[0][i].v){
if(dp[j-G[0][i].v][k][1]!=-1)
dp[j][k][1]=max(dp[j][k][1],dp[j-G[0][i].v][k][1]+G[0][i].w);
if(dp[j-G[0][i].v][k][0]!=-1)
dp[j][k][0]=max(dp[j][k][0],dp[j-G[0][i].v][k][0]+G[0][i].w);
}
if(k>=G[0][i].v){
if(dp[j][k-G[0][i].v][1]!=-1)
dp[j][k][1]=max(dp[j][k][1],dp[j][k-G[0][i].v][1]+G[0][i].w);
if(dp[j][k-G[0][i].v][0]!=-1)
dp[j][k][0]=max(dp[j][k][0],dp[j][k-G[0][i].v][0]+G[0][i].w);
}
}
}
}
ans=0;
for(i=0;i<=V1;i++)
for(j=0;j<=V2;j++)
for(k=0;k<=1;k++)
ans=max(ans,dp[i][j][k]);
printf("Case %d: %d\n\n",cas++,ans);
}
return 0;
}
K
树形dp, 我觉得自己写的没错,但是hdu上就是只写输入都会Tle,根本不知道怎么回事,只能贴一下自己代码了
我的做法:
dfs 回溯,在记录深度,根据深度来选择符合条件的最大或最小值。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll __int64
#define N 500002
struct Edge{
int to,di;
int next;
};
Edge edge[N*2];
int head[N],tot;
void addedge(int u,int v,int d){
edge[tot].to=v;
edge[tot].di=d;
edge[tot].next=head[u];
head[u]=tot++;
}
int dis[N],L,R;
int deep[N],n;
int ans[N];
void dfs(int u,int pre){
int flag=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int to=edge[i].to;
int l=edge[i].di;
if(to==pre) continue;
flag=1;
deep[to]=deep[u]+1;
if(dis[u]>R)
dis[to]=R+1;
else
dis[to]=dis[u]+l;
dfs(to,u);
}
if(!flag) //叶子
if(L<=dis[u] && dis[u]<=R)
ans[u]=dis[u];
if(ans[u]!=-1){
if(ans[pre]==-1 )
ans[pre]=ans[u];
else{
if(deep[pre]&1)
ans[pre]=max(ans[pre],ans[u]);
else
ans[pre]=min(ans[pre],ans[u]);
}
}
}
void init(int n){
memset(dis,0,sizeof(dis));
memset(ans,-1,sizeof(ans));
memset(head,-1,sizeof(head));
deep[0]=1;
dis[0]=tot=0; //所以deep奇数选最大,偶数选最小
}
int main()
{
//freopen("1.txt","r",stdin);
while(~scanf("%d %d %d",&n,&L,&R)){
init(n);
int a,b,c;
for(int i=1;iscanf("%d %d %d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
dfs(0,0);
if(ans[0]==-1) printf("Oh, my god!\n");
else
printf("%d\n",ans[0]);
}
return 0;
}
M
简单dp 都不会也是醉了
只需要想到,对于全排列从 x 到 x+1 长度增加1 对E的影响 要么就不变,要么就+1
于是很简单就可以写出dp方程。。。
N简单的最短路,十个点,任何算法都能过。