noip模拟题11.11 光棍节测试

T1. tractor

题目描述

农场上有N(1 <= N <= 50,000)堆草,放在不同的地点上。FJ有一辆拖拉机,也在农场上。拖拉机和草堆都表示为二维平面上的整数坐标,坐标值在1..1000的范围内。拖拉机的初始位置与所有草堆不同。
FJ开拖拉机时,只能平行于坐标轴(即东、南、西、北四个方向),而且每次开动的一段必须是整数长度。
例如,他可以向北开2个单位长度,然后向东开3个单位长度。拖拉机不能开到草堆的位置。
请帮助FJ计算出最少要移动多少个草堆,他才能将拖拉机开回坐标原点。
拖拉机可以开到1..1000之外的地方去。

输入

第1行: 3个整数,即N 和拖拉机的初始位置 (x,y)
第2..1+N行: 每行2个整数,表示一堆草的位置 (x,y)

输出

第1行: FJ必须移动的最少的草堆的数量

样例输入

7 6 3
6 2
5 2
4 3
2 1
7 3
5 4
6 4

样例输出

1

提示

样例说明:拖拉机初始在(6,3),7 堆草分别在 (6,2), (5,2), (4,3), (2,1), (7,3), (5,4), (6,4).FJ 必须移动一堆草

开始写了个dfs没有剪枝,只过了2个点,而且把题意理解错了,以为是移到格子的另一个地方,而真正是直接把一堆草干掉…
dfs:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int xx[4]={-1,0,1,0},yy[4]={0,-1,0,1};
int map[1050][1050],judge[1050][1050],ans=0x7f7f7f7f;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void dfs(int x,int y,int step,int prex,int prey)
{
    if(step>=ans)return ;
    if(x<1||x>1000||y<1||y>1000)
    {
        ans=min(ans,step);
        if(ans==0)
        {
            printf("0");exit(0);
        }
        return ;
    }
    for(int i=0;i<=3;i++)
    {
        int tmpx=x+xx[i],tmpy=y+yy[i];
        if(tmpx==prex&&tmpy==prey)continue;
        if(!map[tmpx][tmpy]&&judge[tmpx][tmpy]>step)
        {
            judge[tmpx][tmpy]=step;
            dfs(tmpx,tmpy,step,x,y);
        }
        else if(map[tmpx][tmpy]&&judge[tmpx][tmpy]>step+1)
        {
            judge[tmpx][tmpy]=step+1;
            dfs(tmpx,tmpy,step+1,x,y);
        }
    }
}
int main()
{
    freopen("tractor.in","r",stdin);
    freopen("tractor.out","w",stdout);
    int n=read(),stx=read(),sty=read();
    for(int i=1;i<=n;i++)
    {
        int a=read(),b=read();
        map[a][b]=1;
    }
    memset(judge,0x7f7f7f7f,sizeof judge);
    judge[stx][sty]=0;
    dfs(stx,sty,0,-1,-1);
    printf("%d",ans);
    return 0;
}

T2. Landscaping

题目描述

N(1 <= N <= 100)个数排成一行,值分别为A_i,现在希望把每个数对应地改成B_i。(A_i,B_i
的值均在0..10 之间)。改变的方式有3 种:
(1)把A_i 增加到B_i,每增加1,花费 X(2)AiBi1 Y
(3)把第i 个数的值转移到第j 个数,每转移1,花费为$Z*|i-j|
问:最小的花费是多少。

输入

第1 行:4 个整数 N, X, Y, Z (0 <= X, Y, Z <= 1000).
第2..1+N 行: 每行2 个整数 A_i 和 B_i.

输出

第1 行:1 个整数,表示最小的花费。

样例输入

4 100 200 1
1 4
2 3
3 2
4 0

样例输出

210

提示

INPUT DETAILS: There are 4 flowerbeds in a row, initially with 1, 2, 3, and 4 units of dirt. Farmer
John wishes to transform them so they have 4, 3, 2, and 0 units of dirt, respectively. The costs for
adding, removing, and transporting dirt are 100, 200, and 1.
OUTPUT DETAILS: One unit of dirt must be removed (from flowerbed #4), at a cost of 200. The
remaining dirt can be moved at a cost of 10 (3 units from flowerbed #4 to flowerbed #1, 1 unit
from flowerbed #3 to flowerbed #2).

全英文提示很蛋疼…一眼dp无疑,但理不清思路,总感觉有后效性。
记数组 f[i][j] 表示前 i-1 个数已经处理好了,现在处理第 i 个数,前 i 个数一共需要后面转移 j 个数过来。因为 j 有可能时负数,那么我们在基础上加1000。那么当 delta[i]>0 时,f[i][j]=min(f[i-1][j-k]+abs( j-1000 )×z+( delta[i]-k )×x,表明后面转移 k 到 i 这个数的最小代价。delta[i]<0 时,f[i][j]=min(f[i-1][j+k]+abs( j-1000 )×z+(-delta[i]-k )×y。
至于后效性的问题,对于 i,我们可以认为转移到它的数完全由 i+1 转移过来,而最后一个数就不转移。所以我们答案输出 f[n][1000]表示前 n 个数从后面转移 0 个数过来,那么前 n 个数之间就算是处理好了的。
代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int f[1005][2005],delta[1005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    freopen("landscaping.in","r",stdin);
    freopen("landscaping.out","w",stdout);
    int n=read(),x=read(),y=read(),z=read();
    for(int i=1;i<=n;i++)
    {
        int a=read(),g=read();
        delta[i]=g-a;
    }
    memset(f,INF,sizeof f);
    f[0][1000]=0;
    int minx=1000,maxn=1000;
    for(int i=1;i<=n;i++)
    {
        if(delta[i]>0)
        {
            maxn+=delta[i];
            for(int j=minx;j<=maxn;j++)
                for(int k=0;k<=delta[i];k++)
                {
                    int tmp=f[i-1][j-k]+abs(j-1000)*z+(delta[i]-k)*x;
                    f[i][j]=min(f[i][j],tmp);
                }
        }
        else
        {
            minx+=delta[i];
            for(int j=minx;j<=maxn;j++)
                for(int k=0;k<=-delta[i];k++)
                {
                    int tmp=f[i-1][j+k]+abs(j-1000)*z+(-delta[i]-k)*y;
                    f[i][j]=min(f[i][j],tmp);
                }
        }
    }
    printf("%d",f[n][1000]);
}

T3 3.equal

【问题描述】

明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
1. 表达式只可能包含一个变量‘a’。
2. 表达式中出现的数都是正整数,而且都小于10000。
3. 表达式中可以包括四种运算‘+’(加),‘-’(减),’ ’(乘),‘^’(乘幂),以及小括号‘(’,‘)’。小括号的优先级最高,其次是‘^’,然后是’,最后是‘+’和‘-’。‘+’和‘-’的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符‘+’,‘-’,‘*’,‘^’以及小括号‘(’,‘)’都是英文字符)
4. 幂指数只可能是1到10之间的正整数(包括1和10)。
5. 表达式内部,头部或者尾部都可能有一些多余的空格。
下面是一些合理的表达式的例子:
((a^1) ^ 2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1 + (a -1)^3,1^10^9……

【输入文件】

输入文件equal.in的第一行给出的是题干中的表达式。第二行是一个整数n(2 <= n <= 26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D……
输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。

【输出文件】

输出文件equal.out包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。

【样例输入】

( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a

【样例输出】

AC

【数据规模】

对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;
对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。

直接暴力表达式计算,把 a 随便取一个质数,每次计算%一个质数,如果选项中的算出来和题干的一样,输出。ps:这题需要运气,看你选的质数好不好,选得好能A,选的不好要W几个点。
代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 10003
using namespace std;
char symbol[55],g[55];
int p,i;
long long num[55];
void math()
{
    switch(symbol[p--])
    {
        case '+':(num[p]+=num[p+1])%=mod;break;
        case '-':(num[p]-=(num[p+1]-mod))%=mod;break;
        case '*':(num[p]*=num[p+1])%=mod;break;
        case '^':int x=num[p];for(int i=2;i<=num[p+1];i++)(x*=num[p])%=mod;num[p]=x%mod;break;
    }
}
bool judge()
{
    if((g[i]=='+'||g[i]=='-')&&symbol[p]!='(')return 1;
    if(g[i]=='^'&&symbol[p]=='^')return 1;
    if((g[i]=='*'||g[i]=='/')&&(symbol[p]=='*'||symbol[p]=='/'||symbol[p]=='^'))return 1;
    return 0;
}
long long count()
{
    int len=strlen(g);p=1;i=0;
    g[len]=')';symbol[p]='(';
    while(i<=len)
    {
        while(g[i]=='('||g[i]==' ')
        {
            if(g[i]==' ')
            {
                i++;continue;
            }
            symbol[++p]=g[i];i++;
        }
        int x=0;
        if(g[i]=='a')
        {
            x=23333;i++;
        }
        else while(g[i]>='0'&&g[i]<='9')
        {
            x=x*10+g[i++]-'0';
            while(g[i]==' ')i++;
        }
        num[p]=x%mod;
        while(g[i]==' ')i++;
        int q;
        do
        {
            q=1;
            if(g[i]==')')
            {
                while(symbol[p]!='(')
                    math();
                num[p-1]=num[p];
                --p;
            }
            else 
            {
                while(judge())
                    math();
                symbol[++p]=g[i];
            }
            i++;
            while(g[i]==' ')
            {
                i++;q++;
            }
        }while(i<=len&&g[i-q]==')');
    }
    return num[0];
}
int main()
{
    freopen("equal.in","r",stdin);
    freopen("equal.out","w",stdout);
    gets(g);
    long long ans1=count();
    int n;scanf("%d",&n);getchar();
    for(int j=1;j<=n;j++)
    {
        memset(num,0,sizeof num);
        memset(g,0,sizeof g);
        gets(g);
        long long t=count();
        if(t==ans1)
            printf("%c",j+64);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值