POJ 刷题进程.2

POJ 刷题进程.2-(已完结)

POJ 1690 (Your)((Term)((Project)))

题目传送门

题意:

简单的来说就是给你一个只带字母的代数式,里面可能带有一些多余的括号,要求你把这些多余的括号删除。

解题过程:

比较简单的模拟题,只需要注意括号前面有减号是不能删除的就行了。

AC代码:

#include <iostream>  
#include <cstring>  
#include <cstdio>  
#include <cmath>  
#include <algorithm>  
#include <queue>
#include <set>
#include <vector>
#include<stack>  
using namespace std;  

int k[1000];
int cut[1000];
vector <char> ans;

int main()
{
    int t;
    cin >> t;
    getchar();
    while(t--)
    {
        string s;
        getline(cin,s);
        s ="+"+s;
        int len=s.size();
        ans.clear();
        memset(cut, 0, sizeof cut);
        memset(k, 0, sizeof k);
        stack<char>st;
        for (int i=0;i<len;i++)
        {
            if (s[i]=='(')st.push(i);
            else if(s[i]==')')
            {
                int pos=st.top();
                k[i]=pos;
                k[pos]=i;
                st.pop();
            }
        }

        for (int i=0;i<len;i++)
        {
            if (s[i]==' ') continue;
            if (cut[i]) continue;
            if (s[i]=='(')
            {
                if (ans[ans.size()-1]=='+'||ans[ans.size()-1]=='(')
                {
                    cut[i]=1;
                    cut[k[i]]=1;
                }
                else
                {
                    ans.push_back(s[i]);
                }
            }
            else if (s[i]==')')
            {
                ans.push_back(s[i]);
                int len2=ans.size();
                if (len2>=2&&ans[len2-3]=='(')
                {
                    char ch=ans[len2-2];
                    ans.pop_back();
                    ans.pop_back();
                    ans.pop_back();
                    ans.push_back(ch);
                }
            }
            else ans.push_back(s[i]);
        }
        for (int i=1;i<(int)ans.size();i++)cout<<ans[i];
        cout<<endl;
    }
    return 0;
}

POJ 1699 Best Sequence

题目传送门

题意:

给你一些由A T C G组成的字符串,问你将这些字符组成一个字符串最短的长度是多少。

解题过程:

通过题目可以比较明显的看出这题是一个KMP,然后寻找最优解,我们可以发现数据比较小,可以用状压DP解决。

AC代码:

#include <cstdio> 
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
using namespace std;
const int maxn=25;

int T;
int n;
char s[maxn][maxn];
int len[maxn];
int k[maxn][maxn];
int f[1<<12][12];

inline void kmp(int pos)
{
    int i,j;  
    i=0; 
    j=k[pos][0]=-1;  
    while(i<len[pos])  
    {  
        while(j!=-1&&s[pos][j]!=s[pos][i])j=k[pos][j];  
        i++;j++;  
        k[pos][i]=j;  
    }  
} 

inline int get_next(int posa,int posb)
{
    int i,j;  
    i=j=0;  
    while(i<len[posa])  
    {  
        while(j!=-1&&s[posb][j]!=s[posa][i])j=k[posb][j];  
        i++;j++;  
        if(j==len[posb])return 0;  
    }  
    return len[posb]-j;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",s[i]);
            len[i]=strlen(s[i]);
        }
        memset(f,0x3f,sizeof f);
        for(int i=0;i<n;i++)  
        {  
            kmp(i);  
            f[1<<i][i]=len[i];  
        }  

        for(int i=0;i<(1<<n);i++)  
        {
            for(int j=0;j<n;j++)  
            {
                if(i&(1<<j))  
                {
                    for(int k=0;k<n;k++)  
                    {  
                        if(i&(1<<k))continue;  
                        int cnt=get_next(j,k);
                        if(cnt)
                            f[i+(1<<k)][k]=min(f[i+(1<<k)][k],f[i][j]+get_next(j,k));  
                        else 
                            f[i+(1<<k)][j]=min(f[i+(1<<k)][j],f[i][j]);  
                    }  
                }
            }
        }

        int ans=0x3f3f3f3f;  
        for(int i=0;i<n;i++)  
        {
            ans=min(ans,f[(1<<n)-1][i]);
        }  
        printf("%d\n",ans);  
    }
    return 0;
}

POJ 1742 Coins

题目传送门

题意:

一道比较裸的多重背包的题目。

解题过程:

可以采用RMQ或者DP做法,我比较的喜欢用RMQ,但是感觉自己的代码常数有点大,卡了好久才A掉,有兴趣的也可以采用DP做一做。

AC代码:

#pragma GCC optimize (3)
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=100050;

int n,m;
int f[maxn];
int a[maxn],c[maxn];

int main()
{
    while(scanf("%d%d",&n,&m)&&n&&m)
    {
        for(int i=1;i<=m;i++)
        {
            f[i]=0;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        int tot=0;
        for(int i=1;i<=n;i++)
        {
            int cnt;
            scanf("%d",&cnt);
            int sum=1;
            while(sum<cnt)
            {
                c[++tot]=a[i]*sum;
                cnt-=sum;
                sum*=2;
            }
            c[++tot]=a[i]*cnt;
        }
        f[0]=1;
        // for(int i=1;i<=tot;i++)
        // {
        //     printf("%d ",c[i]);
        // }
        // puts("");
        for(int i=1;i<=tot;i++)
        {
            for(int j=m;j>=c[i];j--)
            {
                if(!f[j])
                f[j]=f[j-c[i]];
            }
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            if(f[i])ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

POJ 1887 Testing the CATCHER

题目传送门

题意:

你有一个导弹系统,可以拦截敌方的导弹,但是每次拦截一个导弹之后,下一个拦截的导弹只能比这个导弹的高度要低,按顺序给出你一些导弹的发射高度,问你最多能拦截多少的导弹。

解题过程:

与LIS差不多,只是求最长下降子序列,方法还是差不多的。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
const int maxn=10005;

int a[maxn],f[maxn];

int main()
{
    int n,x,T=0;
    while(scanf("%d",&x))
    {
        if(x==-1) break;
        n=0;
        a[n++]=x;
        while(1)
        {
            scanf("%d",&x);
            if(x==-1) break;
            a[n++]=x;
        }
        f[0]=1;
        int ans=1;
        int temp;
        for(int i=1;i<n;i++)
        {
            temp=0;
            for(int j=0;j<i;j++)
            {
                if(a[j]>a[i]&&temp<f[j])
                temp=f[j];
            }
            f[i]=temp+1;
            if(ans<f[i])
            ans=f[i];
        }
      printf("Test #%d:\n",++T);
      printf("  maximum possible interceptions: %d\n\n",ans);
    }
     return  0;
}

POJ 1936 All in All

题目传送门

题意:

给出两个字符串,问其中一个字符串是否包含另一个字符串。

解题过程:

只需要暴力枚举两个字符串进行比对就行了。

AC代码:

#include <cstdio>
#include <iostream>  
#include <algorithm>  
#include <cmath>  
#include <vector>  
#include <string>  
#include <cstring>  
using namespace std;  
const int maxn=100005;

char a[maxn],b[maxn];

int main()  
{  
    while(scanf("%s%s",a,b)!=EOF)
    {
        int now=0;
        int len1=strlen(a);
        int len2=strlen(b);
        for(int i=0;i<len2;i++)
        {
            if(b[i]==a[now])now++;
        }
        if(now==len1)puts("Yes");
        else puts("No");
    }
    return 0;  
}  

POJ 1952 BUY LOW, BUY LOWER

题目传送门

题意:

你需要去买股票,但你会遵循一个规律,每次买的股票必须低于上一次买的股票的价钱,给出你连续几天的股票,问你最多能够购买多少天的股票,并且输出最优解的方案数。

解题过程:

加强版的最长下降子序列,要求输出方案数,实际上只需要做一些小小的变动,在搜索的时候加上一个数组记录到当前长度的方案个数。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
using namespace std;  
typedef long long ll;
const int maxn=5005;

int f[maxn]; 
ll a[maxn];  
ll cnt[maxn];
int n;

int main()  
{  
    while(scanf("%d",&n)!=EOF)  
    {    
        int maxx=0;  
        for(int i=1;i<=n;i++)  
        {  
            scanf("%lld",&a[i]); 
            f[i]=0;  
            cnt[i]=0;  
        }  
        f[0]=0;  
        a[0]=0x3f3f3f3f;  
        for(int i=1;i<=n;i++)  
        {  
            for(int j=i-1;j>=0;j--)  
            {
                if(a[j]>a[i]&&f[j]+1>f[i])  
                {
                    f[i]=f[j]+1;
                }
            }
            maxx=max(maxx,(int)f[i]);
        }   
        int res=0;  
        cnt[0]=1;  
        for(int i=1;i<=n;i++)  
        {  
            for(int j=i-1;j>=0;j--)  
            {  
                if(f[i]==f[j]&&a[i]==a[j]) 
                    break;  
                if(f[i]==f[j]+1&&a[i]<a[j]) 
                    cnt[i]+=cnt[j];  
            }  
            if(f[i]==maxx&&cnt[i])   
                res+=cnt[i];   
        }  
        printf("%d %d\n",maxx,res);
    }  

    return 0;  
}  

POJ 1953 World Cup Noise

题目传送门

题意:

你需要按要求组成一个字符串,要求字符串只能由0和1组成,并且不能有两个相邻的1,问你组成长度问n的字符串个数有多少。

解题过程:

比较经典的搜索题,可以采用记忆化,f[num][len]表示到长度为len的时候,数字为num的字符串总共有多少种。然后进行搜索就可以了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
using namespace std;
const int maxn=60;

int n;
int f[2][maxn];

inline int dfs(int now,int len)
{
    // printf("%d %d\n",now,len );
    if(f[now][len]!=-1)return f[now][len];
    if(len==n)return 1;
    int ans;
    if(now==0)
    {
        ans=dfs(now,len+1)+dfs(1-now,len+1);
    }
    else ans=dfs(1-now,len+1);
    f[now][len]=max(f[now][len],ans);
    // printf("%d %d %d\n",now,len,f[now][len]);
    return f[now][len];
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int x=1;x<=T;x++)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            f[0][i]=f[1][i]=-1;
        }
        int ans=dfs(1,1)+dfs(0,1);
        printf("Scenario #%d:\n",x);
        printf("%d\n\n",ans);   
    }
    return 0;
}

POJ 1958 Strange Towers of Hanoi

题目传送门

题意:

你有一个新型的汉诺塔,有四根柱子,规则与普通汉诺塔一样,问你把所有的盘子从第一根柱子移到最后一根柱子的最少步骤是多少。

解题过程:

当柱子数为3跟时,移动次数为2^n-1.当柱子数为4的时候,可以利用2根空的柱子移动盘子,盘子数n为1,2,3时只需按顺序移动,各需1,3,5次,4个盘子以上:
(1)首先移动其中的几个盘子
(2)把剩余的盘子移动到指定的位置
(3)把(1)的盘子移动到(2)的上面
执行(1)和(3)的时候有两根空柱子可以利用,执行(2)的时候只有一根柱子利用,此时yu柱子数为3的时候情况相同
例如:当n=4的时候,如果(1)移动2个盘子,则需3次,(2)移动剩下的两个盘子,需要3次,然后把(1)的2个盘子移动到(2)上面也需要3次,共需9次;
如果(1)移动3个盘子,需要5次,(2)移动剩下的1个盘子,需要1次,然后把(1)的3个盘子移动到(2)上面也需要5次,共需11次;
如果(1)移动1个盘子,需要1次,(2)移动剩下的3个盘子,需要7次,然后把(1)的一个盘子移动到(2)上面也需要1次,共9次。
所以9才是最少的移动次数。但是,不知道如何分得到的才是最少的次数。所以要全部求出,比较求出最小的,分别求(k,n-k)(1

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
int tower[13]={0,1,3,5};

int hanoi(int k,int m)
{
    int cost=0;
    cost+=tower[k]*2;      
    cost+=(int)pow(2,m)-1;  
    return cost;
}

int main()
{
    int i,j,cost;
    for(i=1;i<=12;i++)
    {
        if(i>3)
        {
            tower[i]=0x3f3f3f3f;
            for(j=1;j<i;j++)
            {
                cost=hanoi(j,i-j);
                tower[i]=tower[i]>cost?cost:tower[i];
            }
        }
        printf("%d\n",tower[i]);
    }
    return 0;
}

POJ 1959 Darts

题目传送门

题意:

让你玩一个飞镖游戏,游戏的规则与现实中的飞镖游戏一样,让你扔三次飞镖,问你得分刚好是n的方案数。

解题过程:

刚开始觉得这题有点可怕,但是仔细的看了看发现得分的情况只有63种,而且只要投三次飞镖,相当于从这63个数种可重复的取出3个数,问你分数刚好为给定的数的方案数。这就非常的暴力了。。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
using namespace std;
const int maxn=70;

int point[maxn]={1,18,4,13,6,10,15,2,17,3,19,7,16,8,11,14,9,12,5,20,40,2,36,8,26,12,20,30,4,34,6,38,14,32,16,22,28,18,24,10,3,54,12,39,18,30,45,6,51,9,57,21,48,24,33,42,27,36,15,60,0,25,50};
int n;

void FO()
{
    freopen("data.txt","r",stdin);
    freopen("1.txt","w",stdout);
}

int main()
{
    // FO();
    int T;
    scanf("%d",&T); 
    for(int i=1;i<=T;i++)
    {
        scanf("%d",&n);
        int cnt=0;
        for(int i=0;i<63;i++)
        {
            for(int j=i;j<63;j++)
            {
                for(int k=j;k<63;k++)
                {
                    int ans=point[i]+point[j]+point[k];
                    if(ans==n)cnt++;
                }
            }
        }
        printf("Scenario #%d:\n",i);
        printf("%d\n\n",cnt);
    }
    return 0;
}

POJ 1962 Corporative Network

题目传送门

题意:

有n个节点,有两个操作
I x y:把x作为y的子节点连上,他们的距离为abs(x-y)%1000
E x:查询x到根节点的距离
要求每次输出查询的值。

解题过程:

可以发现这题是个并查集,并且还需要进行优化,在并查集维护父亲节点的同时,更新当前节点到根节点的距离就行了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
using namespace std;
const int maxn=20005;

int fa[maxn],dis[maxn];
int T,n;

void init()
{
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        dis[i]=0;
    }
}

int find(int x)
{
    if(fa[x]==x)return x;
    int ffa=find(fa[x]);
    dis[x]+=dis[fa[x]];
    return fa[x]=ffa;
}

void unite(int x,int y)
{
    fa[x]=y;
    dis[x]=abs(x-y)%1000;
    return ;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        char ch;
        while(scanf("%c",&ch))
        {
            if(ch=='O')break;
            if(ch=='E')
            {
                int x;
                scanf("%d",&x);
                find(x);
                printf("%d\n",dis[x]);
            }
            if(ch=='I')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                unite(x,y);
            }
        }
    }
    return 0;
}

POJ 1975 Median Weight Bead

题目传送门

题意:

你有n个珠子,每个珠子的重量各不相同,给出m组关系表示a和b两个珠子的轻重关系,问你再知道这些关系之后,能够确定几个珠子不是珠子重量的中位数。

解题过程:

先用数组mp[i][j]表示i与j的重量关系,0表示未知,-1表示i比j轻,1表示i比j重,然后用Floyd跑一边闭包传递,具体做法就是枚举中间节点k,然后枚举i,j如果mp[i][k]和mp[k][j]都是1或者-1,那么mp[i][j]的值也为1或者-1。然后记录与一个珠子有关的关系,如果比它重的或者轻的超过了一半,那么这个珠子就可以确定了。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
const int maxn=105;

int mp[maxn][maxn];
int T,n,m;

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(mp,0,sizeof mp);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            mp[x][y]=1;
            mp[y][x]=-1;
        }
        for(int k=1;k<=n;k++)
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    if(mp[i][k]==1&&mp[k][j]==1)mp[i][j]=1;
                    if(mp[i][k]==-1&&mp[k][j]==-1)mp[i][j]=-1;
                }
            }
        }
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            int heavy=0,light=0;
            for(int j=1;j<=n;j++)
            {
                if(mp[i][j]==1)heavy++;
                if(mp[i][j]==-1)light++;
            }
            if(heavy>=(n+1)/2||light>=(n+1)/2)cnt++;
        }
        printf("%d\n",cnt);
    }
    return  0;
}

POJ 1989 The Cow Lineup

题目传送门

题意:

给你一个序列,让你从这个序列中寻找出最短的非子序列,求这个子序列的长度是多少。

解题过程:

将集合尽可能划分成多个区间,并满足每个区间包含1..k之间所有的数,如果分成了x个区间,那么这些区间一定包含了所有长度为x的子序列,而没有包含全部的长度为 x+1 的子序列,因为可以通过在每个区间任取一个数来组成长度为 x 的序列。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
using namespace std;

int a[10005];

int main()
{
    int n,k,p,res,num;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        res=num=0;
        memset(a,0,sizeof a);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&p);
            if(!a[p])
            {
                a[p]=1;
                num++;
                if(num==k)
                {
                    res++;
                    memset(a,0,sizeof a);
                    num=0;
                }
            }
        }
        printf("%d\n",res+1);
    }
    return 0;
}

POJ 2018 Best Cow Fences

题目传送门

题意:

给你一个长度为n的序列,要求从这个序列中找出长度不短于f的区间,使得该区间的平均值最大。求这个平均值*1000的值。

解题过程:

用二分枚举平均值ave,每个牛的价值都减去ave,看是否有连续的超过f长度的区间使得这段区间的价值大于等于0,如果能找到,那么说明这个平均值可以达到。然后维护区间可以用前缀和处理,复杂度就不会爆炸了。

AC代码:

#include <cstdio> 
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
using namespace std;
const int maxn=100005;

int n,f;
int a[maxn],pre[maxn];
double p,l=1e9,r=-1;

bool check(double arve)
{
    double ans1=pre[f-1]-(f-1)*arve;
    for(int i=f;i<=n;i++)
    {
        double ans2=pre[i]-pre[i-f]-f*arve;
        ans1=ans1+a[i]-arve;
        ans1=max(ans1,ans2);
        if(ans1>-1e-7)return 1;
    }
    return 0;
}

int main()
{
    scanf("%d%d",&n,&f);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pre[i]=pre[i-1]+a[i];
        r=max(r,(double)a[i]);
        l=min(l,(double)a[i]);
    }
    // for(int i=1;i<=n;i++)
    // {
    //     printf("%d ",pre[i]);
    // }
    // puts("");
    while(r-l>=1e-9)
    {
        double mid=(r+l)/2;
        if(check(mid))
        {
            l=mid;
        }
        else r=mid;
    }
    printf("%d\n",(int)(r*1000));
    return 0;
}

POJ 2029 Get Many Persimmon Trees

题目传送门

题意:

给你一个W*H的矩阵,矩阵中有一些点是有柿子的,你可以选中这个矩阵中长为S,宽为T的矩形,问这个矩形最多能够包含多少个柿子。

解题过程:

典型的前缀和问题,pre[i][j]记录以(1,1)和(i,j)为两个点的矩形中柿子的个数,然后枚举就行了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=505;

int n,w,h,s,t;
int mp[maxn][maxn],pre[maxn][maxn];

void init()
{
    for(int i=1;i<=w;i++)
    {
        for(int j=1;j<=h;j++)
        {
            pre[i][j]=pre[i][j-1]+mp[i][j];
        }
    }
    for(int i=1;i<=w;i++)
    {
        for(int j=1;j<=h;j++)
        {
            pre[i][j]+=pre[i-1][j];
        }
    }
}

int main()
{
    while(scanf("%d",&n)&&n)
    {
        scanf("%d%d",&h,&w);
        memset(mp,0,sizeof mp);
        memset(pre,0,sizeof pre);
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&y,&x);
            mp[x][y]=1;
        }
        // for(int i=1;i<=w;i++)
        // {
        //     for(int j=1;j<=h;j++)
        //     {
        //         if(mp[i][j])printf("*");
        //         else printf("-");
        //     }
        //     puts("");
        // }
        init();
        scanf("%d%d",&s,&t);
        // printf("s:%d t:%d\n",s,t);
        int maxx=-1;
        for(int i=1;i<=w-t+1;i++)
        {
            for(int j=1;j<=h-s+1;j++)
            {
                int cnt=pre[i-1][j-1]+pre[i+t-1][j+s-1];
                cnt=cnt-pre[i-1][j+s-1]-pre[i+t-1][j-1];
                if(maxx<cnt)
                {
                    maxx=cnt;
                    // printf("pos:%d %d %d %d\n",i,j,i+t-1,j+s-1);
                }
            }
        }
        printf("%d\n",maxx);
    }
    return 0;
}

POJ 2039 To and Fro

题目传送门

题意:

你有一份加密过的信,要求你用给定的方法吧这封信解密。

解题过程:

比较水的模拟题,按照题意进行模拟就行了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=205;

int n;
char mp[maxn][maxn],in[maxn];

int main()
{
    while(scanf("%d",&n)&&n)
    {
        scanf("%s",in);
        int len=strlen(in);
        int h=len/n;
        int now=0;
        for(int i=1;i<=h;i++)
        {
            if(i&1)
            {
                for(int j=1;j<=n;j++)
                {
                    mp[i][j]=in[now++];
                }
            }
            else 
            {
                for(int j=n;j>=1;j--)
                {
                    mp[i][j]=in[now++];
                }
            }
        }
        // for(int i=1;i<=h;i++)
        // {
        //     for(int j=1;j<=n;j++)
        //     {
        //         printf("%c ",mp[i][j]);
        //     }
        //     puts("");
        // }
        for(int j=1;j<=n;j++)
        {
            for(int i=1;i<=h;i++)
            {
                printf("%c",mp[i][j]);
            }
        }
        puts("");
    }
    return 0;
}

POJ 2063 Investment

题目传送门

题意:

你要去一家银行买国债,国债有n种,每种有相应的价格和收益,你刚开始有N元,你想要存m年,你要最大化你的收益,问你最多能够得到多少钱。(注:国债的所有价格都是1000的倍数)。

解题过程:

看到题之后应该很快就能够有想法,想到用DP求出当前有i元钱时能够得到的最大的收益,然后一步一步递推上去就行了。但是碍于题目的数据过大,直接这样开数组会MLE,然后我们就可以注意到国债的所有价格都是1000的倍数,也就是说我们在DP时,实际上在1000元以内的部分是不会作出贡献的,更简单的说,就是dp[1000]和dp[1999]无论什么时候的值都是相同的,所以我们就可以把DP的数组缩小1000倍,这样既不会影响答案,也能够减小内存。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=50005;
const int D=15;

int T,n,st,year,d;
int cost[D],ret[D];
int ans[maxn];

inline void DP()
{
    for(int i=0;i<=maxn;i++)
    {  
        ans[i]=-1;
    }
    ans[0]=0;
    for(int i=1;i<=d;i++)
    {
        for(int j=0;j<=maxn-cost[i]/1000-10;j++)
        {
            if(ans[j]<0)continue;
            ans[j+cost[i]/1000]=max(ans[j+cost[i]/1000],ans[j]+ret[i]);
        }
    }
    for(int i=1;i<=maxn-10;i++)
    {
        if(ans[i]<0)ans[i]=ans[i-1];
    }
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(cost,0,sizeof cost);
        memset(ret,0,sizeof ret);
        scanf("%d%d%d",&st,&year,&d);
        for(int i=1;i<=d;i++)
        {
            scanf("%d%d",&cost[i],&ret[i]);
        }
        DP();
        for(int i=1;i<=year;i++)
        {
            int can=st/1000;
            st+=ans[can];
        }
        printf("%d\n",st);
    }
    return 0;
}

POJ 2081 Recaman’s Sequence

题目传送门

题意:

一串数列由0开始,下一项m如果a[m-1]-m大于0,并且这个数在数列中没有出现过,那么下一项等于a[m-1]-m,否则等于a[m-1]+m。

解题过程:

手膜一下发现这题数列到500000的数据似乎并不大,用数组似乎记录的下,所以就可以直接简单的模拟了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=50000005;
const int N=500005;

int a[maxn],k;
bool used[maxn];

void init()
{
    a[0]=0;
    memset(used,0,sizeof used);
    used[0]=1;
    for(int i=1;i<=500002;i++)
    {
        int nxt=a[i-1]-i;
        // printf("%d %d\n",nxt,used[nxt]);
        if(nxt<0||used[nxt])
            a[i]=a[i-1]+i;
        else a[i]=nxt;
        used[a[i]]=1;
        // system("pause");
    }
}

int main()
{
    init();
    while(scanf("%d",&k)&&~k)
    {
        printf("%d\n",a[k]);
    }
    return 0;
}

POJ 2082 Terrible Sets

题目传送门

题意:

这题的题目意思比较难懂,读了半天才读懂,大致意思就是给你连续的n个矩形的长度和高度,问你将这些矩形按顺序并排放在一起,能够得到的面积最大的矩形的面积是多少。

解题过程:

理解了题目意思之后会发现这题就是稍微更改一下的单调栈,简单的模拟即可。

AC代码:

#include <cstdio> 
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
typedef pair<P,int>PI;
#define fi first
#define se second
const int maxn=50005;

int n;
stack<PI>S;
int w[maxn],h[maxn];
P wi[maxn];

int main()
{
    while(1)
    {
        scanf("%d",&n);
        if(n==-1)break;
        memset(w,0,sizeof w);
        memset(wi,0,sizeof w);
        memset(h,0,sizeof h);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&w[i],&h[i]);
        }
        int now=1;
        for(int i=1;i<=n;i++)
        {
            if(S.empty())
            {
                S.push(PI(P(w[i],h[i]),i));
                wi[i].fi=now;
                now+=w[i];
            }
            else 
            {
                P x=S.top().fi;
                if(x.se<=h[i])
                {
                    wi[i].fi=now;
                    S.push(PI(P(w[i],h[i]),i));
                    now+=w[i];
                }
                else 
                {
                    P nowx=S.top().fi;
                    int pos=S.top().se;
                    while(nowx.se>h[i]&&!S.empty())
                    {
                        S.pop();
                        wi[i].fi=wi[pos].fi;
                        wi[pos].se=now;
                        if(!S.empty())
                        pos=S.top().se,nowx=S.top().fi;
                    }
                    S.push(PI(P(w[i],h[i]),i));
                    now+=w[i];
                }
            }  
        }
        while(!S.empty())
        {
            int pos=S.top().se;
            wi[pos].se=now;
            S.pop();
        }
        ll maxx=-1;
        for(int i=1;i<=n;i++)
        {
            ll cnt=wi[i].se-wi[i].fi;
            cnt*=h[i];
            maxx=max(maxx,cnt);
        }
        printf("%lld\n",maxx);
    }
    return 0;
}

POJ 2181 Jumping Cows

题目传送门

题意:

你有n个药水可以给牛喝,你可以跳过一些药水,但是药水的顺序不能变更,在第奇数次喝药水的时候会增加你的跳跃能力,在第偶数次喝下药水的时候回减少你的跳跃能力。求你能得到的最大的跳跃能力。

解题过程:

可以用贪心的方法,因为每瓶药水的值肯定会形成一个波动一样的形状,每次加一个峰值最大的,再加最小的,这样循环。不过要注意的是最后一瓶药水如果是在偶数时间喝下的,那么应该选择不喝。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=150005;

int n;
int a[maxn];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    int f=1;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(f==1)
        {
            while(a[i]<a[i+1])i++;
            ans+=a[i];
            f=-1;
        }
        else 
        {
            while(a[i]>a[i+1])i++;
            if(i<n)
            ans-=a[i];
            f=1;
        }
    }
    printf("%d\n",ans);
    return 0;
}

POJ 2184 Cow Exhibition

题目传送门

题意:

题意是给出n个奶牛的属性值,每个属性包括s和f两种,要求你从中挑出几头牛,使得它们的s的和与f的和都是正数,并且使这两个的和最大。

解题过程:

可以发现这题我们可以当做0背包来做,但是由于s和f有可能出现负的值,所以我们不能用直接把0当做零点。分析一下数据的大小可知这题的s之和在-100000与100000之间,所以我们可以把100000当做零点,然后把所有的点的值都加100000,就可以正常的进行背包了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
const int maxn=200500;
const int N=1005;
const int inf=0x3f3f3f3f;

int dp[maxn];
int n;
int s[N],f[N];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&s[i],&f[i]);
    }   
    for(int i=1;i<=200000;i++)
    {
        dp[i]=-inf;
    }
    dp[100000]=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]<0&&f[i]<0)continue;
        if(s[i]>0)
        {
            for(int j=200000;j>=s[i];j--)
            {
                if(dp[j-s[i]]>-inf)
                {
                    dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
                }
            }
        }
        else 
        {
            for(int j=0;j<=200000+s[i];j++)
            {
                if(dp[j-s[i]]>-inf)
                {
                    dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
                }
            }
        }
    }
    int ans=0;
    for(int i=100000;i<=200000;i++)
    {
        if(dp[i]>=0)
        {
            ans=max(ans,dp[i]+i-100000);
        }
    }
    printf("%d\n",ans);
    return 0;
}

emm……第二套题就在这里了,不幸的是第三套题又来了,继续加油吧……
2018年2月27日07:48:31

转载于:https://www.cnblogs.com/Apocrypha/p/9433673.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值