总结
日期 | 事件 | 刷的题 |
---|---|---|
Day 0(星期天) | 做题 | NOIP2017普及组解题报告 |
Day 1(星期一) | 写博客 | 无 |
Day 2(星期二) | 做题 | 新二叉树,FBI树,数字三角形,吃奶酪,合唱队形,导弹拦截 |
Day 3(星期三) | 讲课 | 一直在改题 |
Day 4(星期四) | 做题 | Asteroids,Knights |
Day 5(星期五) | 刷题 | 最小路径覆盖,增广路导弹拦截第二问,Chessboard |
Day 6(星期六) | 模拟赛 | 模拟赛的题,place the robots,最大正方形,吃吃吃 |
时间复杂度
题目 | 时间复杂度 |
---|---|
第一题 数列 | O(logd(n)) O ( l o g d ( n ) ) |
第二题 蚂蚁 | O(4000n2) O ( 4000 n 2 ) |
第三题 单元格 | O(n2) O ( n 2 ) |
第四题 剪草 | O(n3) O ( n 3 ) |
解题报告
题目
第一题 数列
思路
对于等差数列,直接暴力规律求解,对于等比数列,直接暴力模拟
代码
#include<iostream>
#include<cstdio>
#define ULL unsigned long long
using namespace std;ULL a,b,c,d,n,ans;
int main()
{
cin>>a>>b>>c>>d>>n;//输入
if(n>a)ans=(n-a)/b+1;//计算
while(c<=n)
{
if(c<a||(c-a)%b) ans++;//判断在不在
c*=d;
if(d==1)break;//特判
}
cout<<ans;//输出
}
第二题 蚂蚁
思路
暴力模拟,模拟每只蚂蚁慢慢爬
代码
#include<cstdio>
using namespace std;int n,x,y,ans;char s[51];bool ok;
struct node
{
char w;
double x,y;
}a[51];
double t=2005;//一直爬
bool check(int x)//判断此蚂蚁是否消失
{
return a[x].w=='S'||a[x].w=='N'||a[x].w=='E'||a[x].w=='W';
}
int main()
{
scanf("%d\n",&n);
gets(s+1);
for(int i=1;i<=n;i++)
{scanf("%lf%lf",&a[i].x,&a[i].y);a[i].w=s[i];}//输入+初始化
while(t-=0.5)//继续爬
{
for(int i=1;i<=n;i++)
{
if(a[i].w=='N') a[i].y+=0.5;else
if(a[i].w=='S') a[i].y-=0.5;else
if(a[i].w=='E') a[i].x+=0.5;else
if(a[i].w=='W') a[i].x-=0.5;//爬
}
for(int i=1;i<n;i++)
{
ok=false;
for(int j=i+1;j<=n;j++)
if(a[i].x==a[j].x&&a[i].y==a[j].y&&check(i)&&check(j))//看看有没有蚂蚁会消失
{a[j].w='\0';ok=true;}//标记已经消失
if(ok)a[i].w='\0';//若有蚂蚁消失,此蚂蚁也消失
}
}
for(int i=1;i<=n;i++) ans+=check(i);//判断
printf("%d",ans);//输出
}
第三题 单元格
思路
找规律
代码
#include<cstdio>
using namespace std;long long n,m;int x,y;long long ans;
int main()
{
scanf("%lld%lld%d%d",&n,&m,&x,&y);//输入
for(int i=3;i<=n;i++)
{
for(int j=3;j<=m;j++)
if(((i+j-2)<<1)>=x&&((i+j-2)<<1)<=y)//是否在范围之内
ans+=6*(i-2)*(j-2)*(n-i+1)*(m-j+1);//计算
ans%=1000000007;//记得%
}
printf("%lld",ans);
}
第四题 剪草
思路
显然这题不能用贪心去做,因为如果每次割最长的,那么长得最快的那个又长起来了。如果割掉长得最快的,当你去割别的草的时候,这课草又长起来了。而且每棵草没有必要割两次。
所以想到了动态规划,设
F[j][k]
F
[
j
]
[
k
]
表示前
j
j
棵草,割了次的时候所有草的总长度,显然可以得到动态转移方程
F[j][k]=min(f[j−1][k]+a[j]+b[j]∗i,f[j−1][k−1]+(i−k)∗b[j])
F
[
j
]
[
k
]
=
m
i
n
(
f
[
j
−
1
]
[
k
]
+
a
[
j
]
+
b
[
j
]
∗
i
,
f
[
j
−
1
]
[
k
−
1
]
+
(
i
−
k
)
∗
b
[
j
]
)
(i为时间)
代码
#include<cstdio>
#include<algorithm>
#define r(i,a,b) for(int i=a;i<=b;i++)
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
using namespace std;int n,m,f[56][56];
struct node{int a,b;}c[56];
bool cmp(node x,node y){return x.b<y.b;}
int main()
{
file(grass);
scanf("%d%d",&n,&m);
r(i,1,n) scanf("%d",&c[i].a);
r(i,1,n) scanf("%d",&c[i].b);
stable_sort(c+1,c+1+n,cmp);//按生长速度排序
r(i,0,n)//最多割n次
{
r(j,1,n)
{
f[j][0]=f[j-1][0]+c[j].a+c[j].b*i;//初始化
r(k,1,i) f[j][k]=50234567;
}
r(j,1,n)
r(k,1,i)
f[j][k]=min(f[j-1][k]+c[j].a+c[j].b*i,f[j-1][k-1]+c[j].b*(i-k));//动态转移
if(f[n][i]<=m) return printf("%d",i)&0;//满足条件就输出
}
puts("-1");//否则
}