http://acm.ocrosoft.com/contest.php?cid=1034
NOIP2005普及组第2题 校门外的树
题意 给一段数轴,从0-n, 每次操作给一个l和r 删去l和r范围内的整数点,问最终还剩多少整数点
解 暴力即可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
int n,m;
int x,y;
int s[10010];
while(cin>>n>>m)
{
memset(s,0,sizeof(s));
for(int i=0;i<m;i++)
{
cin>>x>>y;
for(int j=x;j<=y;j++)
s[j]=1;
}
int res=0;
for(int i=0;i<=n;i++)
{
if(!s[i])
res++;
}
cout<<res<<endl;
}
return 0;
}
NOIP2005普及组第3题 采药
题意 采药,给一个背包容量,再给每个药的体积和价值,求最大价值。
解 简单的完全背包问题
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
int t,m;
int s[1010];
int w[1010];
int dp[1010];
while(cin>>t>>m)
{
memset(dp,0,sizeof(dp));
for(int i=0;i<m;i++)
{
cin>>s[i];
cin>>w[i];
}
for(int i=0;i<m;i++)
{
for(int j=t;j>=s[i];j--)
dp[j]=max(dp[j],dp[j-s[i]]+w[i]);
}
cout<<dp[t]<<endl;
}
return 0;
}
NOIP2005普及组第4题 循环
题意 给一个大数,求后k位的数字在该数不停的相乘时重复出现的循环节
解 直接找不现实,需要从低位向高位不断寻找该位的循环节,即在前i位的循环节的基础上寻找第i+1位的循环节,相乘即是前i+1位的循环节,本题需要注意的是最终答案也是大数。。。。
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int L=110000;
int l[11]={1,1,4,4,2,1,1,4,4,2};
int k;
void multiplyh(int x[], int y[], int z[]) {
int up = 0;
for (int ii = 1; ii <= k; ii++) {
for (int j = 1; j <= k; j++)
{
z[ii + j - 1] += (x[j] * y[ii] + up) % 10;
up = (x[j] * y[ii] + up) / 10;
}
up = 0;
}
for (int ii = 1; ii <= k; ii++) {
z[ii + 1] += z[ii] / 10;
z[ii] %= 10;
}
}
void multiplyl(int x[], int yy, int z[]) {
int up = 0;
for (int ii = 1; ii <= k; ii++) {
z[ii] = (x[ii] * yy + up) % 10;
up = (x[ii] * yy + up) / 10;
}
}
int main()
{
string a;
int b[205],c[205],d[205],now[205],last[205],ss[205];
memset(last, 0, sizeof last);
memset(b, 0, sizeof b); memset(now, 0, sizeof now);
memset(d, 0, sizeof d); memset(c, 0, sizeof c); memset(ss, 0, sizeof ss);
cin>>a;
cin>>k;
int n=a.size();
int z=0;
for(int i=n-1;i>=n-k;i--)
c[++z]=a[i]-'0';
for(int i=1;i<=k;i++)
b[i]=c[i];
for(int i=1;i<l[c[1]];i++)
{
memset(d,0,sizeof(d));
multiplyh(b,c,d);
for(int j=1;j<=k;j++)b[j]=d[j];
}
ss[1]=l[c[1]];
for(int i=1;i<=k;i++)now[i]=b[i];
for(int i=1;i<=k;i++)last[i]=now[i];
int pos=2;
int t=0;
while(pos<=k)
{
for(int i=1;i<=k;i++)
{
b[i]=c[i];
}
t=0;
while(t<11)
{
t++;
memset(d,0,sizeof(d));
multiplyh(b,now,d);
for(int j=1;j<=k;j++)
{
b[j]=d[j];
}
if(b[pos]==c[pos])
{
break;
}
memset(d,0,sizeof(d));
multiplyh(last,now,d);
for(int j=1;j<=k;j++)
{
last[j]=d[j];
}
}
if(t>=11){cout<<-1<<endl;return 0;}
for(int j=1;j<=k;j++)now[j]=last[j];
memset(d,0,sizeof(d));
multiplyl(ss,t,d);
for (int i = 1; i <= 100; i++) ss[i] = d[i];
pos++;
}
int flag = 0;
for (int i = 100; i >= 1; i--) {
if (ss[i]) flag = 1;
if (flag) cout << ss[i];
}
cout<<endl;
return 0;
}
2012_p1 质因数分解
题意 求一个数能由2个不同的质数相乘得到,求其中较大的质数
解 如果一个数能由2个不同的质数相乘得到,则不难想到该数只可能有4个因子,即1和其本身和另外2个质数,所以只要从该数的开根号开始向下遍历找到一个可以整除的数即可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
for(int i=sqrt(n*1.0);i>1;i--)
{
if(n%i==0)
cout<<n/i<<endl;
}
}
return 0;
}
2012_p2 寻宝
见下博客:
http://blog.csdn.net/b_r_e_a_d/article/details/79597361
2012_p3 摆花
题意 n种花 每种花最多摆ai盆,一共需要摆m盆且从小到大的顺序,问有多少种摆法
解 一开始想到排列组合,但没想出来,于是想到dp,确实是dp,dp[i][j]表示前i种花中拿出j盆来摆的可能性 具体看代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
while(cin>>n>>m)
{
long long dp[211][211];
memset(dp,0,sizeof(dp));
long long a[211];
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=0;i<=a[1]&&i<=m;i++)
dp[1][i]=1;
for(int i=2;i<=n;i++)
{
for(int k=0;k<=m;k++)
{
for(int j=0;j<=a[i]&&j<=k;j++)
{
dp[i][k]=(dp[i-1][k-j]+dp[i][k])%1000007;
}
}
}
cout<<dp[n][m]%1000007<<endl;
}
return 0;
}
2012_p4 文化之旅
见https://my.csdn.net/imzxww
如果他写了的话。。
比赛安排
题意:2^n支队伍对打,每天每支队伍都要出场且2个队伍必须对打一次,求在2^n-1天里队伍安排如何,需要从小到大安排
解 简单穷举
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;;
int main()
{
int n;
while(cin>>n)
{
int da=pow(2.0,n)-1;
int me=da+1;
bool dp[70][70];
bool vis[70];
memset(dp,0,sizeof(dp));
for(int i=1;i<=da;i++)
{
int q=0;
memset(vis,0,sizeof(vis));
cout<<"<"<<i<<">";
for(int j=1;j<=me;j++)
{
if(vis[j]==1)continue;
vis[j]=1;
for(int k=j+1;k<=me;k++)
{
if(vis[k]==0&&dp[j][k]==0)
{
dp[j][k]=1;
vis[k]=1;
if(q++)cout<<",";
cout<<j<<"-"<<k;
break;
}
}
}
cout<<endl;
}
}
return 0;
}
上下火车
题意 火车从始发站(称为第1站)开出,在始发站上车的人数为a,然后到达第2站,在第2站有人上、下车,但上、下车的人数相同,因此在第2站开出时(即在到达第3站之前)车上的人数保持为a人。从第3站起(包括第3站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到终点站的前一站(第n-1站),都满足此规律。现给出的条件是:共有N个车站,始发站上车的人数为a,最后一站下车的人数是m(全部下车)。试问x站开出时车上的人数是多少?
解 用纸算一算每一站的上车人数与净上车人数即可,与斐波那契数列有关
#include<cmath>
#include<cstdio>
#include<vector>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long int
LL up[10000];
LL down[10000];
LL ck[10000];
int main()
{
LL a, n, m, x;
while (~scanf("%ld %ld %ld %ld", &a, &n, &m, &x))
{
memset(ck, 0, sizeof(ck));
up[1] = a;
down[1] = 0;
ck[1] = a;
bool flag = 0;
for (LL i = 0; i <= m; i++)
{
up[2] = i;
down[2] = i;
ck[2] = ck[1];
for (LL j = 3; j<n; j++)
{
up[j] = up[j - 1] + up[j - 2];
down[j] = up[j - 1];
ck[j] = ck[j - 1] + up[j - 2];
}
if (ck[n - 1] == m)
{
printf("%ld\n", ck[x]);
flag = 1;
break;
}
}
if (!flag)
printf("No answer.\n");
}
return 0;
}