洛谷11月月赛·Day2-2015

好久没有发过题解了。。。虽然发了也没有人看QAQ。。。但是noip的前一天本蒟蒻还是来填noip系列的最后一弹了~~TAT(应该是最后一弹了好悲伤,之后应该就是NOI系列了吧)

访问量上千还是蛮感动的~~感谢各位大神能有时间来看本蒟蒻的博客~ THX

会写出来真正让诸神满意的博客哒~~~

这两个月好颓。。。感觉停课和没停一样。。。对自己我也是呵呵了。。。反正本蒟蒻没人关注。。。这些也无关紧要了。。。

不说颓废的话了。。我还得攒RP呢~~ 毕竟这还不是退役考 ~~~Fighting!

**

T1

**

**

题目描述 Description

**
现在给出一个表达式,形如a1/a2/a3/…/an
如果直接计算,就是一个个除过去,比如1/2/1/4=1/8。
然而小A看到一个分数感觉很不舒服,希望通过添加一些括号使其变成一个整数。一种可行的办法是(1/2)/(1/4)=2。
现在给出这个表达式,求问是否可以通过添加一些括号改变运算顺序使其成为一个整数。
输入输出格式 Input/output
输入格式:
一个测试点中会有多个表达式。
第一行t,表示表达式数量。
对于每个表达式,第一行是n,第二行n个数,第i个数表示ai。
输出格式:
输出t行。
对于每个表达式,如果可以通过添加括号改变顺序使其变成整数,那么输出“Yes”,否则输出“No”
**

**

输入输出样例 Sample input/output

==========================

**
样例测试点#1


输入样例:

2
4
1 2 1 4
5
6 5 7 9 12


输出样例:

Yes
No
**

说明 description

**
对于40%的数据,n<=16
对于70%的数据,n<=100
对于全部数据,2<=n<=10000,1<=t<=100,1<=ai<=maxlongint

可以递归,觉得这样的题,如果用递归写的话会很美~~(当然我的代码很丑QAQ,而且我用的是非递归做法。。。)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

long long gcd(long long a,long long b){return a%b==0?b:gcd(b,a%b);}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        if(n==1)
        {
            long long k;
            scanf("%I64d",&k);
            printf("Yes\n");
        }
        else if(n==2)
        {
            long long w,v;
            scanf("%I64d%I64d",&w,&v);
            if(w%v==0)printf("Yes\n");
            else printf("No\n");
        }
        else
        {
            long long w,v,a,gst;
            scanf("%I64d%I64d",&w,&v);
            gst=gcd(w,v);
            v/=gst;
            bool flag=false;
            for(int i=3;i<=n;i++)
            {
                scanf("%lld",&a);
                gst=gcd(a,v);
                a/=gst;v/=gst;
                if(v==1&&!flag)
                {
                    printf("Yes\n");
                    flag=true;
                }
            }
            if(!flag)printf("No\n");
        }
    }
    return 0;
}

**

T2

**


**

题目描述 Description

**
uim在公司里面当秘书,现在有n条消息要告知老板。每条消息有一个好坏度,这会影响老板的心情。告知完一条消息后,老板的心情等于之前老板的心情加上这条消息的好坏度。最开始老板的心情是0,一旦老板心情到了0以下就会勃然大怒,炒了uim的鱿鱼。
uim为了不被炒,知道了了这些消息(已经按时间的发生顺序进行了排列)的好坏度,希望研究如何不让老板发怒。
uim必须按照时间的发生顺序逐条将消息告知给老板。不过uim可以使用一种叫“倒叙”的手法,例如有n条消息,小a可以从k,k+1,k+2…n,1,2…k-1这种顺序通报。
他希望知道,有多少个k,从k开始通报到n然后从1通报到k-1可以让老板不发怒。


**

输入输出格式 Input/output

**
输入格式:
第一行一个整数n(1 <= n <= 10^6),表示有n个消息。
第二行n个整数,按时间顺序给出第i条消息的好坏度Ai(-1000 <= Ai <= 1000)
输出格式:
一行一个整数,表示可行的方案个数。
**

输入输出样例 Sample input/output

**
样例测试点#1
输入样例

4
-3 5 1 2


输出样例

2

**

说明 description

样例解释

**

**
[5 1 2 -3]或[1 2 -3 5]

对于25%数据n<=1000
对于75%数据n<=10000
对于100%数据n<=10^6

记得是用单调队列维护一下前面的最小值和最大值(QAQ我说不清楚。。。直接看代码吧。。很短的)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=1e6+10;

int a[maxn],sum[maxn],n,sa[maxn],pre[maxn],ans,suc[maxn];
bool g[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
    int mn=0;
    for(int i=n;i;i--)
        sa[i]=mn=min(mn+a[i],a[i]),suc[i]=suc[i+1]+a[i];
    for(int i=1;i<=n;i++)
        pre[i]=min(pre[i-1],sum[i]);
    for(int i=1;i<=n;i++)
        if(sa[i]>=0&&(suc[i]+pre[i-1]>=0))ans++;
    printf("%d",ans);
    return 0;
}

还有一种解法是吞噬算法,脑补一下觉得还不错~~
http://blog.csdn.net/MARSHALBEN/article/details/48765803

推荐看一下~

**

T3

**

石子归并有木有~~~

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int maxn=1e3+10;
priority_queue<int,vector<int>,greater<int> > q;

int p[15],a[40],n,m,k,ans,dp[50][50],sum[50];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        int w;
        scanf("%d",&w);
        q.push(w);
    }
    for(int i=1;i<=k;i++)
    {
        int ans1=1000000000;
        for(int i=1;i<=m;i++)scanf("%d",&p[i]);
        for(int i=1;i<=m;i++)
        {
            a[p[i]]=a[p[i]+m]=q.top();
            q.pop();
        }
        for(int i=1;i<=2*m;i++)
        sum[i]=sum[i-1]+a[i];
        memset(dp,127/3,sizeof(dp));
        for(int i=1;i<=m;i++)dp[i][i]=dp[i+m][i+m]=0;
        for(int l=2;l<=m;l++)
        {
            for(int s=1;s+l-1<=m*2;s++)
            {
                int t=s+l-1;
                for(int k=s;k<t;k++)
                {
                    dp[s][t]=min(dp[s][t],dp[s][k]+dp[k+1][t]+sum[t]-sum[s-1]);
                }
            }
        }
        for(int i=1;i<=m;i++)ans1=min(ans1,dp[i][i+m-1]);
        int sum=0;
        for(int i=1;i<=m;i++)sum+=a[i];
        q.push(sum);
        ans+=ans1;
    }
    printf("%d",ans);
    return 0;
}



——既然选择了远方,便只顾风雨兼程

希望我们不会忘记彼此的初衷

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值