【链接】;click here~~
【A 题 Nth Largest Value】PKU 3781 http://poj.org/problem?id=3781
【题目大意】输入十个数,输出第三大的数
【 B题 . Equal Sum Partitions】PKU 3782 http://poj.org/problem?id=3782
【题目大意】给你一个整数序列,M(M <= 10000)个元素的序列,定义一个An equal sum partition。满足将序列可以分成几个区间,每个区间的和相等
【解题思路】此题坑点:从前往后寻找,如果找到有跟前面已经找到的区间的和相等的区间,继续寻找,直到序列末尾,输出区间之和,否则在之后的序列里找不到,直接输出当前所有数之和!(也就是求不是单调序列)
理解了如此,此题也就可以直接模拟了,数据水~~
代码:
/*
Author :HRW
*/
#include <bits/stdc++.h>
using namespace std;
int a[10010];
int solve(int n)
{
int sum=0;
for(int i=0; i<n; i++){
sum+=a[i];
int s2=0;
for(int j=1+i; j<n; j++){
s2+=a[j];
if(s2>sum) break;
if(s2==sum){
s2=0;
if(j==n-1) return sum;
}
}
}
return sum;
}
int main()
{
int t,m,k,n;
cin>>t;
while(t--)
{
cin>>k>>n;
for(int i=0; i<n; i++)
cin>>a[i];
int ans=solve(n);
printf("%d %d\n",k,ans);
}
return 0;
}
【C.Balls】 PKU 3783 http://poj.org/problem?id=3783
【题目大意】
给定
B (B <= 50)
个一样的球,从
M (M <= 1000)
层楼上一个一个往下扔,存在某个楼层
K
,使得低于它的楼层往下扔球,球不会碎,在第
K
层扔下去会碎。求最坏情况下,需要扔几次才能确定这个
K
。
【解题思路】此题赛后发现是IOI2004的一篇论文,竟然是道动态规划!,当时没有做出来,很经典了,详细题解可以参考论文原文件:click here~~
【D.Running Median】PKU 3784 http://poj.org/problem?id=3784
【题目大意】:一个长度为M(M <= 9999)的序列,每次奇数位的数读入的时候计算前面整个序列的中位数。
【解题思路】二分 + 树状数组
由于数字是int32范围,所以首先需要将所有数离散到下标,枚举每一个数字读入,将对应位的数字下标插入到树状数组中,每当读到奇数个的时候,利用树状数组的成端求和的性质,如果要找第K大的数,那么就二分一个答案,然后查询树状数组,如果求和大于等于K,表示是一个候选解(因为要保证大于等于K的数最小,才是第K大的数),反复二分,直到找到最小的值V满足sum(V) >= K,时间复杂度O(2 *M * log(M) )
比赛时用的模拟
#include <bits/stdc++.h>
using namespace std;
int main()
{
//freopen("1.txt","r",stdin);
int P,n,k;
int a[10000];
scanf("%d",&P);
while(P--)
{
count = 0;
scanf("%d%d",&k,&n);
for(int i = 0; i < n; i++) scanf("%d",&a[i]);
printf("%d %d\n",k,(n + 1) / 2);
for(int i = 1; i <= n; i = i + 2){
count++;
sort(a,a+i);
if(count % 10!=0)
printf("%d ",a[(i-1)/2]);
else
printf("%d\n",a[(i-1)/2]);
}
printf("\n");
}
return 0;
}
二分 + 树状数组
#include<bits/stdc++.h>
using namespace std;
int a[10005],A[10005],p[10005],n;
void add(int i){
while(i<=n){
p[i]+=1;
i+=(i&(-i));
}
}
int sum(int i){
int t=0;
while(i){
t+=p[i];
i-=(i&(-i));
}
return t;
}
int find(int k){
int l=1,r=n,res,mid;
while(l<=r){
mid=(l+r)/2;
if(A[mid]>=k){
r=mid-1;
res=mid;
}
else l=mid+1;
}
return res;
}
int main(){
int cas,casn,i,j;
scanf("%d",&cas);
while(cas--){
scanf("%d %d",&casn,&n);
memset(p,0,sizeof(p));
printf("%d %d\n",casn,n/2+1);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
A[i]=a[i];
}
int tot=n/2+1,cnt=0,pos;
sort(A+1,A+n+1);
for(i=1;i<=n;i++){
pos=find(a[i]);
add(pos);
if(i&1){
cnt++;
int l=1,r=n,mid,res,k=i/2+1;
while(l<=r){
mid=(l+r)/2;
if(sum(mid)>=k){
r=mid-1;
res=mid;
}
else l=mid+1;
}
printf("%d",A[res]);
if(cnt%10==0)printf("\n");
else if(cnt!=tot)printf(" ");
}
}
if(tot%10)printf("\n");
}
return 0;
}
【E.The Next Permutation】 PKU 3785 http://poj.org/problem?id=3785
【题目大意】给定一个可重复元素的排列A[i],求下一个排列。
【解题思路】直接把标题函数用上了,~~>_<
代码:
#include <bits/stdc++.h>
using namespace std;
int a[10000];
int main()
{
char str[10000];
int n;
int m,i,j;
cin>>n;
while(n--)
{
scanf("%d %s",&m,str);
int len=strlen(str);
if(next_permutation(str,str+len)) printf("%d %s\n",m,str);
else printf("%d BIGGEST\n",m);
}
return 0;
}
【
F.Adjacent Bit Counts】PKU 3786
http://poj.org/problem?id=3786
【题目大意】求长度为n的二进制整数中,相邻两个1的对数有k对(可重复使用)的整数个数,题目描述的很清楚了
【解题思路】: 令长度为n,相邻1的对数为k的数的个数为DP[n][k],其中以0结尾的为DP[n][k][0],以1结尾的为DP[n][k][1],那么 DP[n][k] = DP[n][k][0] + DP[n][k][1];
并且有如下状态转移方程:
1) 长度为n-1的二进制数在末尾加上一个0,相邻1的对数不变,所以有:
DP[n][k][0] = DP[n-1][k][0] + DP[n-1][k][1];
2) 长度为n-1的二进制数在末尾加上一个1,相邻1的对数取决于,第n-1位是0还是1,当第n-1位是1,相邻1的对数+1;当第n-1位是0,相邻1的对数不变,所以有:
DP[n][k][1] = DP[n-1][k][0] + DP[n-1][k-1][1];
并且初始状态下DP[0][0][0] = 1, DP[0][0][1] = 0
代码:
/*
Author :HRW
dp三维数组,dp[i][j][k]:n,k,(0,1)
n位数,值位k,末尾为(0,1)
状态转移方程:
dp[i][j][0]+=(dp[i-1][j][0]+dp[i-1][j][1]);
dp[i][j][1]+=(dp[i-1][j][0]+dp[i-1][j-1][1]);
*/
#include <bits/stdc++.h>
using namespace std;
int dp[1010][1010][2];
int solve(int n,int k)
{
memset(dp,0,sizeof(dp));
dp[1][0][0]=dp[1][0][1]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++){
dp[i][j][0]+=(dp[i-1][j][0]+dp[i-1][j][1]);
dp[i][j][1]+=(dp[i-1][j][0]+dp[i-1][j-1][1]);
}
return dp[n][k][0]+dp[n][k][1];
}
int main()
{
int t,m,n,k;
cin>>t;
while(t--)
{
cin>>m>>n>>k;
int ans=solve(n,k);
printf("%d %d\n",m,ans);
}
return 0;
}