头大
这个暑假完就要去搞NOIP了。。。
暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。
。。。T1瓜起T2没推出来T3用BFS没搞出来GG。
前两天的T1要么暴力枚举要么随机排列,结果今天T1我也这么干就没去细推。。。
吃一堑长一智吧。。不然可以130的orz
Fin (40/300)
T1 太空电梯 (10/100)
问题描述
为了解决日渐增长的人口问题,Mstdream率领一个小组到达火星开发新的居住地
地球到火星有一架太空电梯,电梯一次最多承载2个人,最大载重为k
小组一共有n个人,第i个人重量为vi.人们排成一队等候上电梯
上电梯的规则是这样的:
1. 如果电梯是空的,下一个人可以上去
2. 如果电梯有一个人,并且下一个人上电梯不会超重,下一个人可以上去,否则
太空电梯会将前一个人载到火星后返回接下一个人
3. 如果电梯有两个人,下一个人不能上去。
由于管理出现了失误!人们排队的顺序发生了变化.假设人们的顺序是未知的,Mstdream
想知道,太空电梯最多会跑多少趟?
输入格式
第一行两个数n,k
第二行开始n行,每行一个数代表vi
输出格式
输出一个数,代表最坏情况下太空电梯需要跑的趟数
Sample Input
6 6
1
2
3
3
4
5
Sample Output
5
Hint
最坏情况下排队的顺序如下:(2)(5 1)(3)(4)(3)
数据规模
50% n<=10
100%: n<=100000,k<=1000000000,vi<=k
这次失误证明了NOIP考试还是要仔细推不要动不动随机大法暴力枚举(废话)orz
MY.CPP
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
#include<queue>
using namespace std;
int n,k,v[100005];
int cnt=100,ans=0;
int main()
{
//freopen("elevator.in","r",stdin);
//freopen("elevator.out","w",stdout);
cin >> n >> k;
for(int i=1;i<=n;i++)cin >> v[i];
while(cnt--)
{
int jud=0;
random_shuffle(v+1,v+n+1);
for(int i=1;i<n;i++)
{
if(v[i]+v[i+1]<k)i+=1;
jud+=1;
}
ans = max(jud,ans);
}
cout << ans << endl;
}
STD.CPP
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
#include<queue>
using namespace std;
int n,k,v[100005];
int ans=0;
int main()
{
//freopen("elevator.in","r",stdin);
//freopen("elevator.out","w",stdout);
cin >> n >> k;
for(int i=1;i<=n;i++)cin >> v[i];
sort(v+1,v+n+1);
int head=1, tail=n;
while(head<tail)
{
if(v[head]+v[tail]<=k)head+=2,ans+=1;
else head+=1,ans+=2,tail-=1;
}
if(head==tail)ans+=1;
cout << ans << endl;
}
T2 (30/100)
构造
问题描述
注意!这是一道输入已知的构造题
Mstdream需要你的智慧!你将会得到一个数字N,你需要构造一个长度为N的数字串,编号
为1,2……N。你的任务是:构造出一个串,使得:如果第i位和第j位的数字一样,那么
第i+j位和第i位不一样(i可以等于j)
输入格式
输入一个数字N
输出格式
输出一个长度为N的数字串
Sample Input
10
Sample Output
0102010301
数据范围
十个点N分别为
20 500 1023 1024 1400 1899 2200 5000 15000 25000
注意:代码长度不能超出100kb。
傻乎乎(推了半天不知道除此之外还能怎么推)的按着题解上的二进制(后来被我乱搞成了16进制。。(虽然说用十六进制的话能轻松过掉))去推,然后发现到1024时就GG了。后来也没想出解决办法。。。
正解略奇葩,要手推出来。
STD.CPP
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
#include<queue>
using namespace std;
int n,cnt,num;
string c;
int main()
{
//freopen("number.in","r",stdin);
//freopen("number.out","w",stdout);
cin >> n;
c="0110"; num=2; cnt=4;
while(cnt<n)
{
string x;
for(int i=cnt+1;i<=2*cnt+1;i++)x+=num+'0';
cnt+=cnt+1+cnt; c=c+x+c; num+=1;
}
for(int i=0;i<n;i++)cout << c[i];
}
T3 围城
问题描述
僵尸将城市紧紧围住了!
城市被划分成了n*m的方格,方格外充斥着僵尸
每个格子,有三种符号:
X:障碍物,幸存者和僵尸均无法进入
D:幸存者
.:空地,幸存者和僵尸均可以进入
幸存者想通过设立路障来阻碍僵尸来袭的脚步,路障被设立在两个格子之间(见下图)
幸存者领袖Mstdream想知道,最少设立几个路障,才能保证所有幸存者的安全?
输入格式
第一行两个数n,m
后面n行,每行m个字符,保证字符是“XD.”之中的一个
输出格式
一行一个数,表示最少的路障数量
(这里为了排版方便把’.’都改成了’*’)
Sample Input
7 8
XXX..XXX
XXX..XXX
…..XXX
XXX..XXX
XDDDD.XX
XDDDD…
XXXXXXXX
Sample Output
3
Sample Input
5 5
XX.XX
.DDD.
XD.DX
X….
X….
Sample Output
6
数据范围
数据保证所有幸存者构成一个连通块
30% N,M<=5
60% N,M<=50
100% N,M<=150
感谢yl大佬的代码。
不过待我先研究研究。。题解要用到最大流最小割定理。。然而网络流我还没怎么学。。。
STD.CPP
#include<stdio.h>
#include<string.h>
#define min(a,b) (a)<(b)?(a):(b)
int n,m,aim,cnt=1,size=1;
int first[30000],deep[30000],dl[30000],tu[151][151];
char s[151][151];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
struct node{
int to,next,dis;
}edge[200000];
inline int read()
{
int i=0;
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i;
}
inline void ae(int x,int y,int z)
{
edge[++size].to=y;
edge[size].dis=z;
edge[size].next=first[x];
first[x]=size;
}
inline void add(int x,int y,int z)
{
ae(x,y,z);
ae(y,x,0);
}
int dfs(int now,int flow)
{
if(now==aim) return flow;
int f=0;
for(int u=first[now];u&&flow;u=edge[u].next)
if(deep[edge[u].to]==deep[now]+1&&edge[u].dis)
{
int tmp=dfs(edge[u].to,min(flow,edge[u].dis));
f+=tmp;
edge[u].dis-=tmp;
edge[u^1].dis+=tmp;
flow-=tmp;
}
if(!f)deep[now]=-5;
return f;
}
inline bool bfs(int s,int t)
{
memset(deep,0,sizeof(deep));
dl[1]=s;
deep[s]=1;
int head=0,tail=1;
while(head!=tail)
{
++head;
for(int u=first[dl[head]];u;u=edge[u].next)
if(!deep[edge[u].to]&&edge[u].dis)
{
dl[++tail]=edge[u].to;
deep[edge[u].to]=deep[dl[head]]+1;
}
}
return deep[t];
}
inline int dis(int s,int t)
{
register int ret=0;
aim=t;
while(bfs(s,t)) ret+=dfs(s,100000000);
return ret;
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;++i) scanf("%s",s[i]+1);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
tu[i][j]=++cnt;
++cnt;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(s[i][j]=='X') continue;
if(s[i][j]=='D') add(tu[i][j],cnt,100000000);
for(int k=0;k<=3;++k)
{
register int fx=i+dx[k],fy=j+dy[k];
if(fx==0||fx>n||fy==0||fy>m) add(1,tu[i][j],1);
else if(s[fx][fy]!='X') add(tu[i][j],tu[fx][fy],1);
}
}
printf("%d\n",dis(1,cnt));
return 0;
}
感想
这个假期学的还不错就是成绩还。相。当。不。稳。定。。。有时还是会乱想。。开学过后必须每次考试到100以上才能算及格。开学后在学校的时间里多刷题吧orz