noip2010提高组题解

NOIP2010提高组题解

 

 

T1:机器翻译

题目大意:顺序输入n个数,有一个队列容量为m,遇到未出现元素入队,求入队次数。

AC做法:直接开1000的队列模拟过程。

 

T2:乌龟棋

题目大意:有长度为n的棋盘,每个格子对应一个分数,1,2,3,4的卡片共m张,给出四种卡片各自的数量,求改变出牌顺序能获得的最大分数。

思路:开了一个四维的f[i][j][k][l]来表示每张牌有了几张时的最大分数;

F[i][j][k][l]=max(f[i-1][j][k][l],f[i][j-1][k][l],f[i][j][k-1][l],f[i][j][k][l-1])+a[i+2*j+3*k+4*l];

 

#include <iostream>
#include <memory.h>
using namespace std;

int n,m,a[355];
int c[125];
int num[5];
int f[51][51][51][51];

int main()
{
    cin >> n >> m;
    for (int i=1;i<=n;i++)
        cin >> a[i];
    for (int i=1;i<=m;i++)
    {
        cin >> c[i];
        num[c[i]]++;
    }
    for (int i=0;i<=num[1];i++)
        for (int j=0;j<=num[2];j++)
            for (int k=0;k<=num[3];k++)
                for (int l=0;l<=num[4];l++)
                {
                    if (i)
                        f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]);
                    if (j)
                        f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l]);
                    if (k)
                        f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k-1][l]);
                    if (l)
                        f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l-1]);
                    f[i][j][k][l]+=a[i+2*j+3*k+4*l+1];
                }
    cout << f[num[1]][num[2]][num[3]][num[4]] << "\n";
}

 

T3:关押罪犯

题目大意:有n个罪犯要分到2个监狱,有的罪犯间结怨,如果怨气值为c就会发生影响为c的冲突。求最大冲突的最小值。

思路:用并查集来表示监狱,将冲突降序排序,冲突大的尽量分开,

直到矛盾,输出矛盾的冲突值即为最大。

#include <iostream>
#include <algorithm>
using namespace std;

int n,m;
struct node
{
    int a,b,c;
    bool operator < (const node &xx) const
    {
        return c<xx.c;
    }
}e[100011];
int x[40011];

int find(int ax) 
{
    return x[ax]==ax?ax:x[ax]=find(x[ax]);
}

int main()
{
    cin >> n >> m;
    for (int i=1;i<=m;i++)
        cin >> e[i].a >> e[i].b >> e[i].c;
    sort(e+1,e+m+1);
    for (int i=1;i<=n*2;i++)
        x[i]=i; 
    for (int i=m;i>=1;i--)
    {
        int fx=find(e[i].a);
        int fy=find(e[i].b);
        if (fx==fy)
        {
            cout << e[i].c << "\n";
            return 0;
        }
        x[fy]=find(e[i].a+n);
        x[fx]=find(e[i].b+n);
    }
    cout << 0 << "\n";
}

 

T4:引水入城

题目大意:有n*m的矩阵城市群。。。(→_→)第一排靠湖,第n排靠沙漠,每个城市海拔不同,沿湖城市可以造蓄水厂向海拔低的城市送水,求第n排能否都送到水。

       (关于输出)       能:1             不能:0

                              (最少蓄水厂数)     (无水城市数)

思路:可以先bfs一次,如果最后一行没有全覆盖,顺便输出数量就可以结束了。如果全覆盖了,那么就对每个一线城市进行dfs求出它覆盖的n线城市的连续区间。最后进行区间覆盖。

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

int n,m;
int map[501][501];
int num;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
struct ct
{
    int x,y,h;
}tc,nw;
queue<ct> q;
int v[501][501];
struct xd
{
    int l,r;
}g[501];
int f[501];
int now;

void dfs(int ax,int ay)
{
    v[ax][ay]=1;
    if (ax==n)
    {
        g[now].l = min(g[now].l,ay);
        g[now].r = max(g[now].r,ay);
    }
    for (int i=0;i<4;i++)
    {
        int xx=ax+dx[i];
        int yy=ay+dy[i];
        if (xx>n||xx<1||yy>m||yy<1||map[ax][ay]<=map[xx][yy])
            continue;
        if (!v[xx][yy]) 
            dfs(xx,yy);
    }
}

int main()
{
    cin >> n >> m;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            cin >> map[i][j];
    for (int i=1;i<=m;i++)
    {
        tc.x=1;
        tc.y=i;
        tc.h=map[1][i];
        q.push(tc);
        v[1][i]=1;
    }
    while (!q.empty())
    {
        nw=q.front();
        q.pop();
        for (int d=0;d<4;d++)
        {
            tc.x=nw.x+dx[d],tc.y=nw.y+dy[d];
            if (tc.x<1||tc.x>n||tc.y<1||tc.y>m)
                continue;
            tc.h=map[tc.x][tc.y];
            if (!v[tc.x][tc.y] && tc.h<nw.h)
            {
                q.push(tc);
                v[tc.x][tc.y]=1;
            }    
        }
    }
    int ans=0;
    for (int i=1;i<=m;i++)
        if (!v[n][i])
            ans++;
    if (ans>0)
    {
        cout << "0\n";
        cout << ans << "\n";
        return 0;
    }
    cout << "1\n";
    for (int i=1;i<=m;i++)
    {
        memset(v,0,sizeof(v));
        now=i;
        g[now].l=m+1;
        g[now].r=0;
        dfs(1,i);
    }
    f[0] = 0;
    for (int i=1;i<=m;i++)
    {
        f[i]=1<<30;
        for (int j=1;j<=m;j++)
            if (i>=g[j].l && i<=g[j].r)
                f[i]=min(f[i],f[g[j].l-1]+1);
    }
    cout << f[m] << "\n";
}

 

转载于:https://www.cnblogs.com/zcyhhh/p/5687609.html

### NOIP 2017 提高 初赛题目解析 #### Pascal 编程语言的淘汰时间 关于 Pascal 编程语言何时不再被支持的问题,在选项中给出的时间点为 2022 年[^1]。 #### 归并算法最坏情况下的比较次数 对于两个长度均为 n 的有序数 A 和 B 进行归并操作时,如果仅考虑元素之间的比较作为基本运算,则在最坏的情况下,至少需要执行 \(2n - 1\) 次比较才能完成整个过程[^2]。 ```python def merge_sorted_arrays(A, B): merged_array = [] i, j = 0, 0 while i < len(A) and j < len(B): if A[i] <= B[j]: merged_array.append(A[i]) i += 1 else: merged_array.append(B[j]) j += 1 # Append any remaining elements from either list merged_array.extend(A[i:]) merged_array.extend(B[j:]) return merged_array ``` 此代码展示了如何有效地将两个已排序列表合并成一个新的已排序列表,并且在这个过程中进行了必要的比较来决定哪个元素应该先加入到新的列表当中去。当处理到最后一个元素的时候,实际上已经完成了 \(2n-1\) 次比较(假设两部分都含有 n 个不同大小的数),这正好对应于上述提到的最佳下界理论值。 #### 硬币分堆与查找不合格品的方法 给定一数量为 n 枚相同外观但可能有一枚质量不同的硬币成的集合 A ,通过天平称重的方式找出那枚与众不同的假币: 1. 计算 k 值等于向下取整后的 \(\lfloor{n / 3}\rfloor\); 2. 把这些硬币分为三份 X、Y 和 Z,每一份分别有 k 枚; 3. 如果 X 和 Y 的质量不相等的话,那么继续下一步骤;否则跳转至第 5 步; 4. 对较轻的那一侧进一步分割重复以上步骤直到找到唯一可疑对象为止; 5. 当剩下不超过两枚硬币时直接对比即可判断哪一个是异常者;而只有一枚的情况则默认其就是那个特殊个体[^3]. 这种策略利用了三分法的思想,每次都将待测样本缩小三分之一左右的比例,从而提高了效率同时也简化了解决方案的设计难度.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值