Fireworks焦祺_第二周
星期六:
虽然历经波折,但是这道题还是解得比较成功的一道题
有一种很很强烈的感觉,这到是简单题,于是不断地想各种方法解出来
一拿到题我就用直接模拟的方法,但是很容易就出错了
发现如果要完整一点的话就得用DFS了,但是很容易TLE了
后来我想了很多种方法去优化我的DFS----未果
最后一次我HASH都用上了,但是TLE得很惨烈.(下续)
HDOJ 2546饭卡 http://acm.hdu.edu.cn/showproblem.php?pid=2546
Problem Description
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
Input
多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。
Output
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
Sample Input
1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0
Sample Output
-45
32
(续上)
这都不行的话那只有DP了,我的DP很弱,但是后来的一次专题训练让我开了点窍
于是我翻出以前的DP总结出来看,便有了灵感:
这得利于我之前就把题目的化解为求一组的子序列和<=m-5的数里的最大数
听起来很费劲,但是如果要表达得更好恐怕不是一句话可以解决的
求解模型: 求序列的最大上升序列
经典的例题可以访问:
http://blog.csdn.net/jqandjq/archive/2009/02/26/3940712.aspx
具体方法:
建另一个数组.来记录每一遍历到的数的最优情况.
下面是我的代码,于由是从DFS的代码改过来的,所以有一些冗余的部分.
#include <iostream>
#include <algorithm>
using namespace std;
int a[1002];
int b[1002];
void dfs(int x);
int m;
int sum,num,ans,flag;
int main()
{
int i,j,k,n,t;
while(scanf("%d",&n)!=EOF && n)
{
memset(b,0,sizeof(b));
sum = 0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum += a[i];
}
scanf("%d",&m);
if (sum+5 <= m) //如果余额很大的情况
{
printf("%d/n",m-sum);
continue;
}
if (m < 5) //如果本来的余额小于5那么就不用计算了
{
printf("%d/n",m);
continue;
}
sort(a,a+n);
//开始遍历:
//找到临界大于m-5的最小的和
ans = 0;
num = m - 5;
for(i=n-2;i>=0;i--)
{
int maxnum = 0;
for(j=i+1;j<=n-2;j++)
{
if((b[j] > maxnum) && (a[i]+b[j]<=num) )
maxnum = b[j];
}
if(a[i]+maxnum == num)
{
ans = num;
break;
}
else if(a[i]+maxnum < num)
{
b[i] = a[i]+maxnum;
}
if(b[i] > ans)
ans = b[i];
}
printf("%d/n",m-ans-a[n-1]);
}
return 0;
}
星期日:
上星期遗下的题目还有一道没有完成
PKU 2262 Goldbach's Conjecture
http://acm.pku.edu.cn/JudgeOnline/problem?id=2262
主要是用高效点的求素数的方法
#include <iostream>
using namespace std;
const int N = 1000005;
bool a[N];
int p[N];
// bool hash[1000005]; 记录某数是否为素数
void Prime2(int n) //线性法,参数表示要打多少内的素数
{
memset(a, 0, n*sizeof(a[0]));
// memset(hash,0,sizeof(hash));
int num = 0, i, j;
for(i = 2; i < n; ++i)
{
if(!(a[i]))
{
p[num++] = i;
// hash[i] = 1;
}
for(j = 0; (j<num && i*p[j]<n); ++j)
{
a[i*p[j]] = 1;
if(!(i%p[j])) break;
}
}
}
int main()
{
int i,j,k,n,m,t;
Prime2(1000001);
while (scanf("%d",&n)!=EOF && n)
{
for (i=0;p[i]<=n/2;i++)
{
if (hash[n - p[i]])
{
printf("%d = %d + %d/n",n,p[i],n-p[i]);
break;
}
}
}
return 0;
}
星期一:
没办法,要检查题数了,只好狂A简单题咯~~~
HDOJ 1062 Text Reverse http://acm.hdu.edu.cn/showproblem.php?pid=1062
简单的字符串控制,之前好像做过,不过题库里这里还没打勾…..
之前还很菜的时候在训练时还A错了几次..而且没A出来
今天十几分钟自信地A掉.
CODE: (水题不直接贴了)
http://blog.csdn.net/jqandjq/archive/2009/03/23/4018038.aspx
HDOJ 1088 Write a simple HTML Browser
http://acm.hdu.edu.cn/showproblem.php?pid=1088
字符串的控制,理解好题意.
不过这题还是有点变态的.
#include <iostream>
using namespace std;
char str[200];
#define hr "--------------------------------------------------------------------------------"
int main()
{
int i,j,k,n,m,t;
int sum = 0;
// freopen("12.txt","r",stdin);
// freopen("123.txt","w",stdout);
while (scanf("%s",str)!=EOF)
{
if (strcmp(str,"<br>") == 0)
{
sum = 0;
printf("/n");
}
else if (strcmp(str,"<hr>") == 0)
{
if (sum == 0)
{
printf("%s/n",hr);
}
else
{
sum = 0;
printf("/n%s/n",hr);
}
}
else
{
if (sum==0)
{
printf("%s",str);
sum += strlen(str);
}
else
{
if (sum + strlen(str) + 1<=80)
{
printf(" %s",str);
sum += strlen(str) + 1;
}
else
{
printf("/n");
printf("%s",str);
sum = strlen(str);
}
}
}
}
printf("/n");
// fclose(stdout);
return 0;
}
---------------------------------------- FIREWORKS 极限A题 ---------------------------------------------
HDOJ 2502月之数 http://acm.hdu.edu.cn/showproblem.php?pid=2502
可以直接用二进制模拟
但模拟之后却发现有公式
我找到的公式是: a[i] = pow(2,i-1)+(i-1)*pow(2,i-1)/2;
二进制模拟法:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int i,j,k,n,m,t;
int a[22];
a[0] = 0;
a[1] = 1;
a[2] = 3;
a[3] = 8;
m = 8;
int num = 0;
for (i=4;i<=20;i++)
{
j = pow(2,i-1); //个数
int sum = 0;
for (k=0;k<j;k++)
{
n = m+k;
for (t=0;t<i;t++)
{
if ((n>>t)&1 == 1)
{
sum++;
}
}
}
m = n+1;
a[i] = sum;
}
// for (i=0;i<=20;i++)
// {
// printf("%d ",a[i]);
// }
while (scanf("%d",&t)!=EOF)
{
while (t--)
{
scanf("%d",&n);
printf("%d/n",a[n]);
}
}
return 0;
}
公式法:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int i,j,k,n,m,t;
int a[22];
for (i=1;i<21;i++)
{
a[i] = pow(2,i-1)+(i-1)*pow(2,i-1)/2;
// cout<<a[i] <<" ";
}
while (scanf("%d",&t)!=EOF)
{
while (t--)
{
scanf("%d",&n);
printf("%d/n",a[n]);
}
}
return 0;
}
HDOJ 2212 DFS http://acm.hdu.edu.cn/showproblem.php?pid=2212
比较有技术含量的做法是:
for(i=11;i<=362800;i++) //一个十位数的各位阶乘和最多为362800
最为猥琐的做法是: main{printf("1/n2/n/145/n40585/n");}
星期二:
HDOJ 1041 Computer Transformation
http://acm.hdu.edu.cn/showproblem.php?pid=1041
简单的大数应用,但很久没有写大数的题WA了几次
a[i][j+1] = a[i][j] / 10; //进位
a[i][j] = a[i][j] % 10;
但不是简单的大数A+B,所以进位时要注意 /10;
改过来之后还是WA
于是怀疑自己推的公式不正确
看了下别人的公式
if( i % 2 == 0 ) times = times * 2 + 1 ;
else times = times * 2 - 1 ;
换了下公式还是WA
幸好不小心测了n=1的数据,发觉大数操作一个重要的地方漏了.
全0的时候要打1个0出来~~
改了下就AC,不过别人推出来的公式不好控制
我的公式也是对的:
a[i] = a[i-1] +a[i-2] *2;
#include <iostream>
using namespace std;
int a[1002][500] = {0};
int main()
{
int i,j,k,n,m,t;
a[0][0] = 0;a[1][0] = 0;a[2][0] = 1;a[3][0] = 1;
for(i=4;i<=1000;i++)
{
for(j=0;j<500;j++)
{
a[i][j] += a[i-1][j] +a[i-2][j]*2;
if(a[i][j] > 9)
{
a[i][j+1] = a[i][j] / 10;
a[i][j] = a[i][j] % 10; //进位
}
}
}
while (scanf("%d",&n)!=EOF)
{
int flag = 0;
if (n == 1 || n == 0)
{
printf("0/n");
continue;
}
for (i=500-1;i>=0;i--)
{
if (a[n][i] != 0 || flag == 1)
{
flag = 1;
printf("%d",a[n][i]);
}
}
printf("/n");
}
return 0;
}
PKU 1458 Common Subsequence
http://acm.pku.edu.cn/JudgeOnline/problem?id=1458
LCS经典例题
和数塔的感觉有点像,就是一路地记录下N*M种可能时的最优解.
求解的主要代码:
if (a[i] == b[j]) maxlen[i][j] = maxlen[i-1][j-1] + 1; //如果相等
else maxlen[i][j] = maxlen[i-1][j] > maxlen[i][j-1] ? maxlen[i-1][j] : maxlen[i][j-1];
PKU 1159 Palindrome http://acm.pku.edu.cn/JudgeOnline/problem?id=1159
还是LCS,但数据改到了5000, 很容易超内存,要注意!
我用的是滑动数组的方法实现内存优化的:
#include <iostream>
using namespace std;
char a[5001];
int y[5001];
int temp[5001];
int main()
{
short i,j,n;
while (scanf("%d",&n)!=EOF)
{
scanf("%s",a+1);
for (i=0;i<5001;i++)
{
y[i] = temp[i] = 0;
}
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
{
if (a[i] == a[n-j+1]) //如果相等
{
if (j-1 == 0)
{
temp[j] = 1;
}
else
temp[j] = y[j-1] + 1;
}
else // 如果不相等
{
if (j-1 == 0)
{
temp[j] = y[j];
}
else
temp[j] = y[j] > temp[j-1] ? y[j] : temp[j-1];
}
}
for (j=1;j<=n;j++)
{
y[j] = temp[j];
temp[j] = 0;
}
}
printf("%d/n",n - y[n]);
}
return 0;
}
星期二:
LSC经典例题:2250 Compromise
http://acm.pku.edu.cn/JudgeOnline/problem?id=2250
代码较长,不直接贴啦~,需要的话点以下链接,我把它挂上面了:
http://blog.csdn.net/jqandjq/archive/2009/03/25/4024660.aspx
PKU 2081 Recaman's Sequence
http://acm.pku.edu.cn/JudgeOnline/problem?id=2081
单简题:用一个表记录下就OK了~
#include <iostream>
using namespace std;
int a[500001];
bool hash[7000002] = {0};
int main()
{
int n,m,i,j,k;
a[0] = 0;
for (i=1;i<=500000;i++)
{
if (a[i-1] - i > 0 && (!hash[a[i-1] - i]))
{
a[i] = a[i-1] - i;
hash[a[i]] = 1;
}
else
{
a[i] = a[i-1] + i;
hash[a[i]] = 1;
}
}
while (scanf("%d",&n)!=EOF && n!=-1)
{
printf("%d/n",a[n]);
}
return 0;
}
PKU 1953 World Cup Noise
http://acm.pku.edu.cn/JudgeOnline/problem?id=1953.
说是DP,但不用DP~简单题~~~
Pku 1080 Humman Gene Function
http://acm.pku.edu.cn/JudgeOnline/problem?id=1080
比较麻烦的DP,代码有点长,请访问:
http://blog.csdn.net/jqandjq/archive/2009/03/26/4027715.aspx
星期三:
HDOJ 2192 Zipper
http://acm.pku.edu.cn/JudgeOnline/problem?id=2192
晚上要讨论的题之一,先A一下
也是LCS的思想,关键是去找状态转移方程
AC CODE:
#include <iostream>
using namespace std;
#define maxlen 205
char a[maxlen]; //行
char b[maxlen]; //列
char str[maxlen*2];
bool recode[maxlen][maxlen] ;
// b a
int main()
{
int i,j,k,n,m,t,l;
while (scanf("%d",&t)!=EOF)
{
for (l=1;l<=t;l++)
{
memset(a+1,NULL,sizeof(a+1));
memset(b+1,NULL,sizeof(b+1));
memset(str+1,NULL,sizeof(str+1));
memset(recode,0,sizeof(recode));
scanf("%s",a+1);
scanf("%s",b+1);
scanf("%s",str+1);
int alen = strlen(a+1);
int blen = strlen(b+1);
recode[0][0] = 1;
for (i=0;i<=blen;i++) //列 b[]
{
for (j=0;j<=alen;j++) //行 a[]
{
if (i==0 && j==0)
{
continue;
}
if (recode[i-1][j] == 0 && recode[i][j-1] == 0 )
{
recode[i][j] = 0;
}
else if ((recode[i-1][j]&&str[i+j]==b[i]) || (recode[i][j-1]&&str[i+j]==a[j]))
{
recode[i][j] = 1;
}
}
}
//---------------------------------------------------
if (recode[blen][alen])
{
printf("Data set %d: yes/n",l);
}
else
{
printf("Data set %d: no/n",l);
}
}
}
return 0;
}
PKU 2479 Maximum sum
http://acm.pku.edu.cn/JudgeOnline/problem?id=2479
又一晚上讨论题
关键求两个最大连续子序列
我设计的算法: 前后各算出 求解最大和:
M |
| 9 | 9 | 9 | 7 | 5 | 5 | 5 | 5 | 5 | -5 |
右 |
| 9 | 8 | 9 | 7 | 5 | 2 | 5 | 1 | 5 | -5 |
原 |
| 1 | -1 | 2 | 2 | 3 | -3 | 4 | -4 | 5 | -5 |
左 |
| 1 | 0 | 2 | 4 | 7 | 4 | 8 | 4 | 9 | 4 |
M |
| 1 | 1 | 2 | 4 | 7 | 7 | 8 | 8 | 9 | 9 |
CODE:
#include <iostream>
using namespace std;
int a[50005];
int lmax[50005];
int rmax[50005];
int main()
{
int i,j,k,n,m,t;
while (scanf("%d",&t)!=EOF)
{
while (t--)
{
scanf("%d",&n);
int sum = 0;
int maxsum =0;
for (i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum += a[i];
if (sum > maxsum)
{
maxsum = sum;
}
if (sum < 0)
{
rmax[i] = a[i];
sum = 0;
}
else
{
rmax[i] = maxsum;
}
}
sum = 0; maxsum =0;
for (i=n-1;i>=0;i--)
{
sum = 0;
sum += a[i];
if (sum > maxsum)
{
maxsum = sum;
}
if (sum < 0)
{
lmax[i] = a[i];
sum = 0;
}
else
{
lmax[i] = maxsum;
}
}
//打完表
//---------------------------------------
//做数据比较处理:
maxsum = 0;
for (i=0;i<n-1;i++)
{
if (rmax[i]+lmax[i+1] > maxsum)
{
maxsum = rmax[i] + lmax[i+1];
}
}
printf("%d/n",maxsum);
}
}
return 0;
}