【洛谷月赛】洛谷10月月赛参·最后的狂欢

洛谷2655 2038年问题

本题地址: http://www.luogu.org/problem/show?pid=2655

题目描述

网络时代,机会与危机共存。“千年虫”解决之后,会不会有新的“虫”出现?回答是肯定的,“2038年”就是一个新的关卡。
也许大家都已经知道计算机的2000年问题是什么概念,但是什么时候又冒出来一个2038年问题的呢?
用C语言编制的程序不会碰到2000年问题,但是会有2038年问题。这是因为,大多数C语言程序都使用到一个叫做“标准时间库”的程序库,这个时间库用一个标准的4字节也就是32位的形式来储存时间信息。
当初设计的时候,这个4字节的时间格式把1970年1月1日凌晨0时0分0秒作为时间起点,这时的时间值为0。以后所有的时间都是从这个时间开始一秒一秒累积得来的。
比方说如果时间已经累积到了919642718这个数值,就是说这时距离1970年1月1日凌晨0时0分0已经过去了919642718秒,换算一下就应该是1999年2月21日星期天16时18分38秒。
这样计算时间的好处在于,把任意两个时间值相减之后,就可以很迅速地得到这两个时间之间相差的秒数,然后你可以利用别的程序把它换算成明白易懂的年月日时分秒的形式。
一个4字节也就是32位的存储空间的最大值是2147483647,请注意!2038年问题的关键也就在这里———当时间一秒一秒地跳完2147483647那惊心动魄的最后一秒后,它就会转为负数也就是说时间无效。那一刻的准确的时间为2038年1月19日星期二晚上03:14:07,之后所有用到这种“标准时间库”的C语言程序都会碰到时间计算上的麻烦。
你要解决的问题是,现有一台计算机,表示时间的变量长度为N位。给定一个“时间起点”,求出对于这个“时间起点”时间,最后的有效时间是什么时候。

输入输出格式

输入格式:

第一行为数据组数T
第2……T+1行,每行7个数字描述一组数据,分别为表示时间的变量长度(二进制位数),然后是“时间起点”的年份,月份,日期,小时,分钟,秒数。

输出格式:

T行,对于每组数据,输出1行,6个数字,分别表示最后的有效时间的年份,月份,日期,小时,分钟,秒数。

输入输出样例

输入样例#1:

1                             
16 2000 1 1 0 0 0

输出样例#1:

2000 1 1 9 6 7

输入样例#2:

2
32 1970 1 1 0 0 0
32 2015 11 8 8 30 0

输出样例#2:

2038 1 19 3 14 7
2083 11 26 11 44 7

说明

对于50%的数据 变量的位数<=16;
对于所有数据,变量长度<=32,数据组数<=1000,0<=年份<=10000


看完题就弃了,交样例0分…


洛谷2658 汽车拉力比赛

本题地址: http://www.luogu.org/problem/show?pid=2658

题目描述

博艾市将要举行一场汽车拉力比赛。
赛场凹凸不平,所以被描述为M*N的网格来表示海拔高度(1≤ M,N ≤500),每个单元格的海拔范围在0到10^9之间。
其中一些单元格被定义为路标。组织者希望给整个路线指定一个难度系数D,这样参赛选手从任一路标到达别的路标所经过的路径上相邻单元格的海拔高度差不会大于D。也就是说这个难度系数D指的是保证所有路标相互可达的最小值。任一单元格和其东西南北四个方向上的单元格都是相邻的。

输入输出格式

输入格式:

第一行两个整数M和N。第2行到第M+1行,每行N个整数描述海拔高度。第2+M行到第1+2M
行,每行N个整数,每个数非0即1,1表示该单元格是一个路标。

输出格式:

一个整数,即赛道的难度系数D。

输入输出样例

输入样例#1:

3 5 
20 21 18 99 5  
19 22 20 16 26
18 17 40 60 80
1 0 0 0 1
0 0 0 0 0
0 0 0 0 1

输出样例#1:

21

水题,二分。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int size=550;

int n,m;
int maps[size][size],s[size][size];
struct xy{
    int x,y;
    xy(int x=0,int y=0):x(x),y(y){};
}start;

queue<xy> q;

bool vis[size][size];

const int dx[]={0,-1,0,1,0};
const int dy[]={0,0,1,0,-1};

void bfs(int d)
{
    q.push(start);
    vis[start.x][start.y]=1;
    while(q.size())
    {
        xy f=q.front(); q.pop();
        for(int i=1;i<=4;i++)
        {
            int x=f.x+dx[i];
            int y=f.y+dy[i];
            if(x>0&&x<=n&&y>0&&y<=m&&!vis[x][y]&&abs(maps[x][y]-maps[f.x][f.y])<=d)
            {
                vis[x][y]=1;
                q.push(xy(x,y));
            }
        }
    }
}


bool checkvis()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]&&!vis[i][j]) return false;
        }
    }   
    return true;
}

bool check(int d)
{
    memset(vis,0,sizeof(vis));
    bfs(d);
    if(checkvis()) return true;
    else return false;
}

int div()
{
    int l=-1,r=1000000000;
    while(r-l>1)
    {
        int mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid;
    }
    return r;
}


int main()
{

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&maps[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&s[i][j]);
            if(s[i][j]) start.x=i,start.y=j;
        }
    }   

    printf("%d",div());

    return 0;
}
/*
5 5

*/


洛谷2657 低头一族

本题地址: http://www.luogu.org/problem/show?pid=2657

题目描述

一群青年人排成一队,用手机互相聊天。
每个人的手机有一个信号接收指标,第i个人的接收指标设为v[i]。
如果位置在x[i]的人要和位置在xj的人聊天,那么这两人组成的一对的信号发射强度就是abs(x[i]-x[j])*max(v[i],v[j]).
现在我们想知道,这些人所有对子中的信号发射强度的总和。

输入输出格式

输入格式:

第一行一个整数N,接下来N行,每行两个整数v[i]和x[i]。

输出格式:

所有对的信号发射强度总和。

输入输出样例

输入样例#1:

4
3 1
2 5
2 6
4 3

输出样例#1:

57

说明

对于40%的数据,N<=5,000
对于100%的数据,N<=100,000 1≤x[i]≤20,000
注意:可能有两人在同一个位置
答案在int64或long long范围内


一开始以为前缀和后缀和推个公式就可以了,结果被abs恶心…

先按v从小到大排序,然后两个树状数组:一个维护x的和,一个维护x的个数。
(大小是x的范围,也就是20000)
然后对于其中一个x,它所做的贡献就是:

(x*比他小的x的个数-比他小的x之和 + 比他大的x之和-x*比他大的x的个数)*v

这个可以树状数组logn维护。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int size=100010;
typedef long long LL;
struct haha{
    LL v,x;
}l[size];

bool cmp(haha a,haha b)
{
    return a.v<b.v;
}

LL bit1[size],bit2[size];
int maxn=20001;

void add1(int x,LL d)
{
    for(int i=x;i<=maxn;i+=(i&-i))
    {
        bit1[i]+=d;
    }
}
LL sum1(int x)
{
    LL ans=0;
    for(int i=x;i>0;i-=(i&-i))
    {
        ans+=bit1[i];
    }
    return ans;
}
void add2(int x,LL d)
{
    for(int i=x;i<=maxn;i+=(i&-i))
    {
        bit2[i]+=d;
    }
}
LL sum2(int x)
{
    LL ans=0;
    for(int i=x;i>0;i-=(i&-i))
    {
        ans+=bit2[i];
    }
    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&l[i].v,&l[i].x);
    }
    sort(l+1,l+1+n,cmp);
    LL ans=0;
    for(int i=1;i<=n;i++)
    {
        add1(l[i].x,l[i].x);
        add2(l[i].x,1);
        LL lans=sum1(l[i].x-1);
        LL ltime=sum2(l[i].x-1);
        LL rans=sum1(maxn)-sum1(l[i].x);
        LL rtime=sum2(maxn)-sum2(l[i].x);
        ans+=( (l[i].x*ltime-lans) + (rans-rtime*l[i].x) )*l[i].v;
    }
    printf("%lld",ans);
    return 0;
}


洛谷2656 采蘑菇

本题地址: http://www.luogu.org/problem/show?pid=2656

题目描述

小胖和ZYR要去ESQMS森林采蘑菇。
ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇。由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。
比如,一条路上有4个蘑菇,这条路的“恢复系数”为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.
现在,小胖和ZYR从S号小树丛出发,求他们最多能采到多少蘑菇。
对于30%的数据,N<=7,M<=15
另有30%的数据,满足所有“恢复系数”为0
对于100%的数据,N<=80,000,M<=200,000,0.1<=恢复系数<=0.8且仅有一位小数,1<=S<=N.

输入输出格式

输入格式:

第一行,N和M
第2……M+1行,每行4个数字,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。
第M+2行,一个数字S

输出格式:

一个数字,表示最多能采到多少蘑菇,在int32范围内。

输入输出样例

输入样例#1:

3 3
1 2 4 0.5
1 3 7 0.1
2 3 4 0.6
1

输出样例#1:

8

tarjan找scc模板题,感觉这个题用来练tarjan挺棒的。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
const int size=1000010;

int head[size],nxt[size],tot=0;

struct edge{
    int t,d;
}l[size];

void build(int f,int t,int d)
{
    l[++tot].t=t;
    l[tot].d=d;
    nxt[tot]=head[f];
    head[f]=tot;
}

int low[size],dfn[size],dfs_clock=0;
int scccnt=0,sccnum[size];
stack<int> s;
void dfs(int u)
{
    dfn[u]=low[u]=++dfs_clock;
    s.push(u);
    for(int i=head[u];i;i=nxt[i])
    {
        int v=l[i].t;
        if(!dfn[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccnum[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        scccnt++;
        while(233)
        {
            int x=s.top(); s.pop();
            sccnum[x]=scccnt;
            if(x==u) break;
        }
    }
}
int value[size];
double hf[size];
int n,m;
bool vis[size];

int getvalue(int d,double haha)
{
    int ans=0;
    while(d)
    {
        ans+=d;
        d*=haha;
    }
    return ans;
}

void getv(int u,int d)
{
    for(int i=head[u];i;i=nxt[i])
    {
        int v=l[i].t;
        if(sccnum[v]==d)
        {
            value[d]+=getvalue(l[i].d,hf[i]); l[i].d=0;
            if(!vis[v])
            {
                vis[v]=1;
                getv(v,d);
            }
        }
    }
}

void init()
{
    memset(nxt,0,sizeof(nxt));
    memset(head,0,sizeof(head));
    memset(l,0,sizeof(l));
    tot=0;
}

deque<int> q;
bool use[size];
int dist[size];
int spfa(int s)
{
    dist[s]=value[s];
    q.push_front(s);
    use[s]=1;
    while(q.size())
    {
        int f=q.front(); q.pop_front();
        use[f]=0;
        for(int i=head[f];i;i=nxt[i])
        {
            int v=l[i].t;
            if(dist[v]<dist[f]+l[i].d+value[v])
            {
                dist[v]=dist[f]+l[i].d+value[v];
                if(!use[v])
                {
                    use[v]=1;
                    if(q.empty()) q.push_front(v);
                    else if(dist[q.front()]<dist[v])
                        q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=scccnt;i++) ans=max(ans,dist[i]);
    return ans;
}
int ff[size],tt[size],dd[size];
bool calc[size];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%lf",&ff[i],&tt[i],&dd[i],&hf[i]);
        build(ff[i],tt[i],dd[i]);
    }
    int s;
    scanf("%d",&s);
    dfs(s);
//  for(int i=1;i<=n;i++) cout<<sccnum[i]<<" ";puts("");
    for(int i=1;i<=n;i++)
    {
        if(!calc[sccnum[i]]) calc[sccnum[i]]=1,getv(i,sccnum[i]);
    }   
    init();
    for(int i=1;i<=m;i++)
    {
        if(sccnum[ff[i]]!=sccnum[tt[i]])
        {
            build(sccnum[ff[i]],sccnum[tt[i]],dd[i]);
    //      cout<<sccnum[ff[i]]<<" "<<sccnum[tt[i]]<<" "<<dd[i]<<endl;
        }
    }
    printf("%d",spfa(sccnum[s]));
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值