Test 10 for NOIP

本文总结了一次NOIP竞赛的备战经历,包括太空电梯、构造题和围城三道题目,涉及算法策略如随机化、排序和网络流等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

头大

这个暑假完就要去搞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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值