# 2018SCUACM Training 3 二分/背包/并查集

## A - Bone Collector

HDU - 2602

Output

Sample Input
1
5 10
1 2 3 4 5
5 4 3 2 1
Sample Output
14

01背包问题是一个经典的DP问题，即动态规划

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1005
#define maxv 1005
using namespace std;
long long max(long long a, long long b)
{
return a > b ? a : b;
}
long long cost[maxn],value[maxn],dp[maxn][maxv];
int main()
{
int T,n,v,i,j;
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&v);
for(i = 1; i <= n; i++)
scanf("%lld",&value[i]);
for(i = 1; i <= n; i++)
scanf("%lld",&cost[i]);
for(i = 1; i <= n; i++)
for(j = 0; j <= v; j++)
{
//dp[i][j]：前i个物品容量最多为j时价值的最大值
dp[i][j] = max(dp[i][j], dp[i-1][j]);//不选第i个物品
if(j >= cost[i])//如果可以选第i个物品
dp[i][j] = max(dp[i][j], dp[i-1][j-cost[i]]+value[i]);
}
printf("%lld\n",dp[n][v]);
}
return 0;
}

## B - The Suspects

POJ - 1611

Input

n = m = 0表示输入结束，不需要处理。
Output对于每组测试数据, 输出一行可能的患者。Sample Input
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
Sample Output
4
1
1

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 30005
int s[maxn];
int root(int x)// find the root of s[x]
{
if(s[x] == x)
return x;
return s[x] = root(s[x]);
}
int main()
{
int n,m,i,k,t,last,cnt;
while(1)
{
scanf("%d%d",&n,&m);
if(n == 0 && m == 0)//multiple data
break;
for(i = 0; i <= n; i++)//initialize
s[i] = i;
cnt = 0;
for(i = 0; i < m; i++)
{
scanf("%d",&k);//number of groups
last = -1;
while(k--)
{
scanf("%d",&t);
if(last == -1)//the first man of the group
last = t;
else
s[root(t)] = root(last);//unite people of thte group
}
}
t = root(0);
for(i = 0; i < n; i++)//count the answer
if(root(i) == t)
cnt++;
printf("%d\n",cnt);
}
return 0;
}

## C - 4 Values whose Sum is 0

POJ - 2785

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .
Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2 28 ) that belong respectively to A, B, C and D .
Output
For each input file, your program has to write the number quadruplets whose sum is zero.
Sample Input
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45

Sample Output
5

Hint
1.Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30). 2.consider changing four lists into two lists.

#include<cstdio>
#include<algorithm>
#define maxn 4005
using namespace std;
int a[maxn],b[maxn],c[maxn],d[maxn];
int sum_cd[maxn*maxn];
int n;
int bin_search(int num)
{
int l = 0, r = n*n;
while(l < r)
{
int m = (l+r) / 2;
if(sum_cd[m] == num)
return m;
if(sum_cd[m] < num)
l = m+1;
else r = m;
}
return -1;
}
int cd_count(int index)
{
int l, r, key;
l = r = index;
key = sum_cd[index];
while(r+1 < n*n && sum_cd[r+1] == key)
r++;
while(l-1 >= 0 && sum_cd[l-1] == key)
l--;
return r-l+1;
}
int main()
{
int i,j,t,cnt;
while(scanf("%d",&n) != EOF)
{
cnt = 0;
for(i = 0; i < n; i++)
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
sum_cd[i*n+j] = c[i]+d[j];
sort(sum_cd,sum_cd+n*n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
t = bin_search(-a[i]-b[j]);
if(t != -1)
cnt += cd_count(t);
}
printf("%d\n",cnt);
}
return 0;
}

## D - Wireless Network

POJ - 2236

1. "O p" (1 <= p <= N)，表示维护电脑 p 。
2. "S p q" (1 <= p, q <= N)，表示测试电脑 p 和 q 是否能够通信。

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4


FAIL
SUCCESS

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 1005
#define maxd 20005
using namespace std;
typedef struct
{
int pre,x,y;
} node;
node a[maxn];
int fix[maxn];
int dist[maxn][maxn];
double dis_squ(node a, node b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int root(int index)
{
if(a[index].pre == index)
return index;
return a[index].pre = root(a[index].pre);
}
int main()
{
int n,d;
memset(dist,0,sizeof(dist));
memset(fix,0,sizeof(fix));
scanf("%d%d",&n,&d);
for(int i = 0; i <= n; i++)
a[i].pre = i;
for(int i = 1; i <= n; i++)
scanf("%d%d",&a[i].x, &a[i].y);
getchar();
for(int i = 1; i <= n; i++)
for(int j = i+1; j <= n; j++)
dist[i][j] = dist[j][i] = dis_squ(a[i],a[j]);
char c;
while(scanf("%c",&c) != EOF)
{
if(c == 'O')
{
int p;
scanf("%d",&p);
while(getchar() != '\n');
fix[p] = 1;
for(int i = 1; i <= n; i++)
if(fix[i] && dist[i][p] <= d*d)
a[root(i)].pre = root(p);
}
else if(c == 'S')
{
int p,q;
scanf("%d%d",&p,&q);
while(getchar() != '\n');
printf(root(p) == root(q) ? "SUCCESS\n":"FAIL\n");
}
}
return 0;
}

## E - The Frog's Games

HDU - 4004

Input

Output

Sample Input
6 1 2
2
25 3 3
11
2
18
Sample Output
4
11

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 500005
#define maxm 500005
using namespace std;
int l,n,m;
int a[maxn];
int isAccess(int dis)//每次跳的最大距离为dis时能否到达终点
{
if(dis < a[0])
return 0;
int cur = 0;//当前位置
int time = m;//跳跃次数
while(time--)
cur = *(upper_bound(a,a+n+1,cur+dis)-1);
return cur >= l;
}
int main()
{
int i,mid_dis,max_dis,min_dis,dis;
while(scanf("%d%d%d",&l,&n,&m) != EOF)
{
dis = max_dis = l;//最好的情况，每次跳的距离为l(或大于l)，跳一次就能跳到对岸
min_dis = 1;//最坏的情况，每次跳的距离为1，跳l次才能跳到对岸
for(i = 0; i < n; i++)
scanf("%d",&a[i]);
a[n] = l;
sort(a,a+n+1);
while(max_dis >= min_dis)
{
mid_dis = (max_dis+min_dis)/2;
if(isAccess(mid_dis) == 0)//每次最多跳mid_dis不能到达终点
min_dis = mid_dis+1;//最少也要跳mid_dis+1才能到达
else//每次最多跳mid_dis可以到达
{
if(dis > mid_dis)//更新dis
dis = mid_dis;
max_dis = mid_dis-1;//找比dis小的范围内还有没有能到达的
}
}
printf("%d\n",dis);
}
return 0;
}

## F - FATE

HDU - 2159

Input输入数据有多组，对于每组数据第一行输入n，m，k，s(0 < n,m,k,s < 100)四个正整数。分别表示还需的经验值，保留的忍耐度，怪的种数和最多的杀怪数。接下来输入k行数据。每行数据输入两个正整数a，b(0 < a,b < 20)；分别表示杀掉一只这种怪xhd会得到的经验值和会减掉的忍耐度。(每种怪都有无数个)Output输出升完这级还能保留的最大忍耐度，如果无法升完这级输出-1。Sample Input
10 10 1 10
1 1
10 10 1 9
1 1
9 10 2 10
1 1
2 2
Sample Output
0
-1
1

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n;//升最后一级还需要的经验值
int m;//剩余的忍耐度
int k;//怪的种数
int s;//最多杀的怪的个数
int a[105];//杀掉第i只怪可以获得的经验值
int b[105];//杀掉第i只怪会减少的忍耐度
int dp[105][105];//dp[i][j]表示在i的忍耐度下杀j只怪能得到的最多的经验
int main()
{
while(scanf("%d%d%d%d",&n,&m,&k,&s) == 4)
{
memset(dp,0,sizeof(dp));
for(int i = 1; i <= k; i++)
scanf("%d%d",&a[i],&b[i]);
int flag = 1;
int ans = -1;
for(int i = 1; i <= m && flag; i++)//遍历忍耐度
for(int j = 1; j <= s && flag; j++)//遍历杀的怪物数
for(int p = 1; p <= k && flag; p++)//遍历k种怪物
{
if(i >= b[p])//忍耐度大于第p个怪物的消耗
dp[i][j] = max(dp[i][j], dp[i-b[p]][j-1]+a[p]);
if(dp[i][j] >= n)
{
ans = m - i;
flag = 0;
}
}
printf("%d\n",ans);
}
return 0;
}


## G - 食物链

POJ - 1182

1） 当前的话与前面的某些真的话冲突，就是假话；
2） 当前的话中X或Y比N大，就是假话；
3） 当前的话表示X吃X，就是假话。

Input

Output

Sample Input
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5

Sample Output
3

【同样的i对应的3个事件是互斥的】，【而不同的的事件之间是互相独立的】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a[150005];
int root(int index)
{
if(a[index] == index)//index指向a[index]，a[index]指向自己，则不需要更新
return a[index];
return a[index] = root(a[index]);
}
int main()
{
int n,k,ans;
int i,d,x,y;
scanf("%d%d",&n,&k);
ans = 0;
for(i = 0; i <= 3*n; i++)//并查集初始化
a[i] = i;
while(k--)
{
scanf("%d%d%d",&d,&x,&y);
if(d != 1 && d != 2)
ans++;//命令格式错误
else if(x < 1 || x > n || y < 1 || y > n)
ans++;//下标错误
else
{
if(d == 1)//x和y是同类
{
if(root(x) == root(y+n) || root(x) == root(y+2*n))
ans++;
else
{
a[root(x)] = root(y);
a[root(x+n)] = root(y+n);
a[root(x+2*n)] = root(y+2*n);
}
}
else//d==2,x吃y
{
if(root(x) == root(y) || root(x) == root(y+2*n))//若已经有xy同类或x被y吃
ans++;
else
{
a[root(x)] = root(y+n);
a[root(x+n)] = root(y+2*n);
a[root(x+2*n)] = root(y);
}
}
}
}
printf("%d\n",ans);
return 0;
}

#include<cstdio>
const int N=50001;
int p[N],r[N],n;
int findset(int x)
{
if(x!=p[x])
{
int fx=findset(p[x]);
r[x]=(r[x]+r[p[x]])%3;
p[x]=fx;
}
return p[x];
}
bool Union(int d,int x,int y)
{
int fx=findset(x),fy=findset(y);
if(fx==fy)
{
if((r[y]-r[x]+3)%3!=d)return 1;
else return 0;
}
p[fy]=fx;
r[fy]=(r[x]-r[y]+d+3)%3;
return 0;
}
int main()
{
int k,count,i,d,x,y;
scanf("%d%d",&n,&k);
count=0;
for(i=1;i<=n;i++)p[i]=i,r[i]=0;
while(k--)
{
scanf("%d%d%d",&d,&x,&y);
if(x>n||y>n||(x==y&&d==2)){count++;continue;}
if(Union(d-1,x,y))count++;
}
printf("%d\n",count);
return 0;
}

## H - A very hard mathematic problem

HDU - 4282

Haoren is very good at solving mathematic problems. Today he is working a problem like this:
Find three positive integers X, Y and Z (X < Y, Z > 1) that holds
X^Z + Y^Z + XYZ = K
where K is another given integer.
Here the operator “^” means power, e.g., 2^3 = 2 * 2 * 2.
Finding a solution is quite easy to Haoren. Now he wants to challenge more: What’s the total number of different solutions?
Surprisingly, he is unable to solve this one. It seems that it’s really a very hard mathematic problem.
Now, it’s your turn.
Input　　There are multiple test cases.
For each case, there is only one integer K (0 < K < 2^31) in a line.
K = 0 implies the end of input.

Output　　Output the total number of solutions in a line for each test case.
Sample Input
9
53
6
0
Sample Output
1
1
0


Hint
9 = 1^2 + 2^2 + 1 * 2 * 2
53 = 2^3 + 3^3 + 2 * 3 * 3


#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int k;
ll ipow(ll a, ll b)
{
if(b == 0)
return 1;
ll x = ipow(a,b/2);
if(b%2) return x*x*a;
else return x*x;
}
void solve()
{
int cnt = 0;
//z=2时，(x+y)²=k
if(((int)sqrt(k))*((int)sqrt(k)) == k)
cnt += (sqrt(k)-1)/2;//x!=y
//z>=3时
ll maxz = (ll)(log(k)/log(2));
for(ll z = 3; z <= maxz; z++)
{
ll maxy = (ll)pow(k,1.0/z);
// printf("maxy=%lld\n",maxy);
for(ll x = 1; x < maxy; x++)
{
ll ly = x+1;//y > x
ll ry = maxy+1;
ll t = ipow(x,z);
while(ly < ry)
{
ll mid = (ly+ry)/2;
// printf("%lld %lld %lld %d\n", x,mid,z,k);
if(t + ipow(mid,z) + x*mid*z == k)
{
cnt++;
break;
}
else if(t +  ipow(mid,z) + x*mid*z < k)
ly = mid+1;
else if(t + ipow(mid,z) + x*mid*z > k)
ry = mid;
}
}
}
printf("%d\n",cnt);
}
int main()
{
while(scanf("%d",&k) && k != 0)
solve();
return 0;
}


• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120