**CCF 全国信息学奥林匹克联赛(NOIP2016)复赛
模拟训练 9.11**
这次考试发现了很多问题(170)
最大的问题就是写程序的时候不细心,T1很水的二分+bfs(MST?)但我的n写成m,浪费了很多时间。
幸亏没有过了样例就就不管了,后天的考试中多造几组数据(现在还不会对拍)
T2 像这样很难想出正解的,骗到尽可能多的分之后下一题,不要浪费太多时间
T3 一个广搜拿50分,这种能拿的分不能丢。正解是hash处理10^9 的数据
%%%Asia 连续两次机房rank1!%%
(请选手务必仔细阅读本页内容)
1、干草(outofhay)
水二分
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=2010;
const int MAXM=20010;
int n,m,x,y,z;
struct Edge{
int next,to,dis;
}edge[MAXM];
int bian[MAXM];
int team[MAXM];
bool vis[MAXN];
int head[MAXN],num_edge;
void add_edge(int from,int to,int dis)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
edge[num_edge].dis=dis;
head[from]=num_edge;
}
bool judge(int len)
{
int tot=1;
memset(vis,0,sizeof(vis));
vis[1]=1; team[1]=1;
int front=0,tail=1;
while (front<=tail)
{
int now=team[++front]; vis[now]=1;
for (int i=head[now]; i!=0; i=edge[i].next)
{
if (!vis[edge[i].to]&&edge[i].dis<=len)
{
vis[edge[i].to]=1;
tot++;
team[++tail]=edge[i].to;
}
}
}
if (tot==n) return true;//
else return false;
}
int main()
{
freopen("outofhay.in","r",stdin);
freopen("outofhay.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++)
{
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z); add_edge(y,x,z);
bian[i]=z;
}
sort(bian+1,bian+1+m);
int l=0,r=m;
while (l<r)
{
int mid=(l+r)/2;
if (judge(bian[mid])) r=mid;
else l=mid+1;
}
printf("%d",bian[l]);
fclose(stdin); fclose(stdout);
return 0;
}
/*
4 6
1 2 50
1 3 1
2 3 1
1 4 200
3 4 70
4 2 150
3 3
1 2 23
2 3 1000
1 3 43
43
*/
2.分解数
(dec.cpp/c/pas)
【问题描述】
Dpstr学习了动态规划的技巧以后,对数的分解问题十分感兴趣。
Dpstr用此过程将一个正整数x分解成若干个数的乘积:一开始令集合A中只有一个元素x,每次分解时从A中取一个元素a并找出两个大于1且互质的整数p,q,要求pq=a,然后将a分解成两个元素p和q,也就是从A中删去a并加入p和q。Dpstr把正整数x用该过程能分解的次数的最大值称为x的分解数。
例如66的分解数为2,因为最多分解2次。一种分解过程为:一开始A={66},第1次将66分解为11×6,此时A={11,6},第2次将6分解为2×3,此时A={11,2,3},之后无法分解。还可以知道,11,2,3的分解数均为0,因为它们一开始就无法分解。
不过只分解一个数对Dpstr来说不够有趣。Dpstr生成了一个包含n个正整数的数列a1, a2, …, an,请你回答有多少对正整数(l,r)满足1≤l≤r≤n且lcm(al, al+1, …, ar-1, ar)的分解数恰为k。其中lcm(al, al+1, …, ar-1, ar)表示数列从第l项到第r项的所有数的最小公倍数,特别地,当l=r时,lcm(al)=al。由于答案可能很大,只需输出满足条件的正整数对个数除以10,007的余数。
【输入格式】
输入文件名为dec.in。
第一行包含两个正整数n,k,意义如题目所示。
第二行包含n个用空格隔开的正整数,分别表示a1, a2, …, an。
【输出格式】
输出文件名为dec.out。
输出一行一个整数,表示满足条件的正整数对个数除以10,007的余数。
【输入输出样例1】
dec.in dec.out
3 1
2 3 6 4
见选手目录下的dec/dec1.in和dec/dec1.ans。
【输入输出样例1说明】
考虑所有满足1≤l≤r≤4的正整数对(l,r):
1、对于(1,1),lcm(2)=2,分解数为0;
2、对于(2,2),lcm(3)=3,分解数为0;
3、对于(3,3),lcm(6)=6,分解数为1;
4、对于(1,2),lcm(2,3)=6,分解数为1;
5、对于(2,3),lcm(3,6)=6,分解数为1;
6、对于(1,3),lcm(2,3,6)=6,分解数为1。
其中,6的分解数为1是因为{6}可以分解为{2,3},之后无法分解。
因此共有4对正整数(l,r)满足条件。
【输入输出样例2】
dec.in dec.out
10 2
2 3 2 6 15 5 5 5 2 3 29
见选手目录下的dec/dec2.in和dec/dec2.ans。
【输入输出样例3】
见选手目录下的dec/dec3.in和dec/dec3.ans。
【数据规模与约定】
对于20%的数据,1≤n≤10,1≤k≤5,1≤ai≤20;
对于40%的数据,1≤n≤100,1≤k≤10,1≤ai≤100;
对于60%的数据,1≤n≤1,000,1≤k≤1,000,1≤ai≤100,000;
对于100%的数据,1≤n≤1,000,000,1≤k≤5,000,000,1≤ai≤10,000,000。
参悟的学姐的blog半天没参悟出来。只能等到noip之后了:
3.推冰块
(ice.cpp/c/pas)
【问题描述】
Dpstr最近迷上了推冰块。冰地是一个n行m列的网格区域,第i行第j列的格子记为(i,j),也就是左上角为(1,1),右下角为(n,m)。每个格子可能是冰面、障碍物、减速带三者之一。其中,冰地外围(即第0行、第n+1行、第0列、第m+1列)的所有格子均有障碍物。除此之外,冰地内共有k个障碍物和减速带,其余格子为冰面。
初始时,有一个冰块位于(1,1)处。Dpstr每次可以选择上、下、左、右四个方向之一推动该冰块,推动后该冰块将一直沿此方向移动,直到冰块所在的格子为减速带,或冰块沿运动方向的下一个格子为障碍物时,冰块将停止运动。一旦冰块停在减速带上,该减速带即消失。
如下图,当n = 5,m = 5时,若冰块位于(3,1),且(3,4)处有一个障碍物,那么向右推动冰块(图1中A处),冰块将停在(3,3)(图1中B处);而如果(3,4)处不是障碍物而是减速带,那么冰块将停在(3,4)上(图2中B处),之后(3,4)处的减速带就会消失。
Dpstr希望通过尽量少的推动次数使得冰块停在(n,m)处。请计算Dpstr至少要推多少次冰块。
【输入格式】
输入文件名为ice.in。
输入的第一行包含三个整数n,m,k,表示冰地大小为n × m,冰地内障碍物和减速带共有k个。
接下来k行,每行包含三个整数xi,yi,ti,描述一个障碍物或减速带。若ti = 0,则表示(xi,yi)处有一个障碍物;若ti = 1,则表示(xi,yi)处有一个减速带。保证同一位置不会有多个障碍物或减速带,且(1,1)处和(n,m)处不会有障碍物或减速带。
【输出格式】
输出文件名为ice.out。
输出仅一行,包含一个整数,表示将冰块推到(n,m)处的最少推动次数。
数据保证至少存在一种将冰块推到(n,m)处的方案。
【输入输出样例1】
ice.in ice.out
4 3 2
1 2 1
4 2 0 3
见选手目录下的ice/ice1.in和ice/ice1.ans。
【输入输出样例1说明】
如图3,至少推3次,一种方案为依次向右、向右、向下推动。
【输入输出样例2】
见选手目录下的ice/ice2.in和ice/ice2.ans。
【数据规模与约定】
对于30%的数据,2≤n≤5,2≤m≤5,0≤k≤5;
对于50%的数据,2≤n≤1,000,2≤m≤1,000,0≤k≤1,000;
对于70%的数据,2≤n≤50,000,2≤m≤50,000,0≤k≤50,000;
对于100%的数据,2≤n≤1,000,000,000,2≤m≤1,000,000,000,0≤k≤50,000,1≤xi≤n,1≤yi≤m,0≤ti≤1。
能一眼看出是广搜吧
code(50)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=5001;
int dx[5]={0,0,0,1,-1},
dy[5]={0,1,-1,0,0};
//障碍物 1 减速带 2
int n,m,k;
int g[MAXN][MAXN];
struct Node{
int x,y,step;
};
queue <Node> que;
void bfs()
{
while (!que.empty())
{
Node now=que.front(); que.pop();
for (int i=1; i<=4; i++)
{
int xx=now.x; int yy=now.y;
bool flag=false;
while (xx+dx[i]>=1&&xx+dx[i]<=n&&yy+dy[i]>=1&&yy+dy[i]<=m&&g[xx+dx[i]][yy+dy[i]]!=1)
{
xx+=dx[i]; yy+=dy[i];
if (g[xx][yy]==2) {g[xx][yy]=0; flag=true; break;}
}
if (xx==now.x&&yy==now.y) continue;
if (!flag)
{
if (g[xx][yy]==-1) continue;
g[xx][yy]=-1;
}/**/
if (xx==1&&yy==1) continue;
if (xx==n&&yy==m) {printf("%d",now.step+1); return;}
Node tmp;
tmp.x=xx; tmp.y=yy; tmp.step=now.step+1;
que.push(tmp);
}
}
}
int main()
{
// freopen("ice.in","r",stdin);
// freopen("ice.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for (int i=1; i<=k; i++)
{
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
if (t==0) g[x][y]=1;
if (t==1) g[x][y]=2;
}
Node stat;
stat.x=1; stat.y=1; stat.step=0;
que.push(stat);
bfs();
return 0;
}
/*
4 3 2
1 2 1
4 2 0
3
*/
正解:(写ci了版,也是等到noip后了)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int MAXN=1e5+7;
int dx[5]={0,0,0,1,-1},
dy[5]={0,1,-1,0,0};
int n,m,k,step[MAXN],ha[MAXN];
struct Zhang{
int x,y,z;
}a[MAXN],b[MAXN];
struct Node{
int x,y;
};
queue <Node> que;
bool compA(Zhang a,Zhang b)//上左优先
{
if (a.y!=b.y) return a.x<b.x;
else return a.y<b.y;
}
bool compB(Zhang a,Zhang b)//左上优先
{
if (a.x!=b.x) return a.y<b.y;
else return a.x<b.x;
}
int hash(int x,int y)
{
int k=(x-1)*m+y;//k这个数是不能变的
int t=k%MAXN;
while (ha[t]&&ha[t]!=k) t++;
return ha[t]=t;//返回的是t 在hash中的位置
}
void judge(Node tmp)
{
if (tmp.x==n&&tmp.y==m)
{
int h=hash(tmp.x,tmp.y);
printf("%d",step[h]);
exit(0);
}
}
void find_LR(Node now)
{
int l=0,r=k;
//find Left
while (l<r)
{
int mid=(l+r)/2;
if (a[mid].x>now.x||(a[mid].x==now.x&&a[mid].y>=now.y)) r=mid;
else l=mid+1;
}
int p=hash(now.x,now.y);
if (a[l].x!=now.x)//左边没有障碍物,可以一直走到最左边
{
Node tmp; tmp.x=now.x; tmp.y=1;
int to=hash(tmp.x,1);//在hash表里面标记这个点已经走过了
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
else
{
Node tmp; tmp.x=now.x; tmp.y=now.y;
if (a[l].z==0) tmp.y++;
int to=hash(tmp.x,tmp.y);
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
//find Right
l=0; r=k;
while(l<r)
{
int mid=(l+r)/2;
if (a[mid].x<now.x||(a[mid].x==now.x&&a[mid].y<=now.y)) l=mid+1;
else r=mid;
}
if (a[l].x!=now.x)
{
Node tmp; tmp.x=now.x; tmp.y=m;
int to=hash(tmp.x,tmp.y);
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
else
{
Node tmp; tmp.x=a[l].x; tmp.y=a[l].y;
if (a[l].z) tmp.y--;
int to=hash(tmp.x,tmp.y);
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
}
void find_FB(Node now)
{
int p=hash(now.x,now.y);
//find Front
int l=0; int r=k;
while (l<r)
{
int mid=(l+r)>>1;
if (b[mid].y>now.y||(b[mid].y==now.y&&b[mid].x>=now.x)) r=mid;
else l=mid+1;
}
if (a[l].y!=now.y)
{
Node tmp; tmp.y=now.y; tmp.x=1;
int to=hash(tmp.x,tmp.y);
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
else
{
Node tmp; tmp.x=now.x; tmp.y=now.y;
if (b[l].z) tmp.x--;
int to=hash(tmp.x,tmp.y);
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
//find Behind
l=0; r=k;
while (l<r)
{
int mid=(l+r)>>1;
if (b[mid].y<now.y||(b[mid].y==now.y&&b[mid].x<=now.x)) l=mid+1;
else r=mid;
}
if (b[l].y!=now.y)
{
Node tmp; tmp.x=n; tmp.y=now.y;
int to=hash(tmp.x,tmp.y);
if (step[to]<0)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
else
{
Node tmp; tmp.x=b[l].x; tmp.y=b[l].y;
if (b[l].z) tmp.x++;
int to=hash(tmp.x,tmp.y);
if (step[to]==-1)
{
step[to]=step[p]+1;
que.push(tmp); judge(tmp);
}
}
}
void bfs()
{
Node stat; stat.x=1; stat.y=1; que.push(stat);
step[hash(1,1)]=0;
while (!que.empty())
{
Node now=que.front(); que.pop();
find_LR(now);
find_FB(now);
}
}
int main()
{
freopen("ice.in","r",stdin);
freopen("ice.out","w",stdout);
memset(step,-1,sizeof(step));
scanf("%d%d%d",&n,&m,&k);
for (int i=1; i<=k; i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
b[i].x=a[i].x; b[i].y=a[i].y; b[i].z=a[i].z;
}
sort(a+1,a+1+k,compA);
sort(b+1,b+1+k,compB);
bfs();
return 0;
}
/*
4 3 2
1 2 1
4 2 0
3
*/
PS:明天早上8:30就要发车去日照。真有一种上战场的赶脚呢。
祝我好运