topcoder div 2 (1)

10 篇文章 0 订阅
9 篇文章 0 订阅

A

时间限制: 1 Sec  内存限制: 128 MB

题目描述

有两个正整数A和B,两个操作+3或者-2。

问,至少多少次操作可以让A变到B

输入

多组数据,第一行一个整数T(1<=T<=5)

两个整数A和B(1<=A,B<=100)

输出

最少操作次数

样例输入

3 10 14 23 23 18 12

样例输出

3 0 3

 

一道水题,各种方法

我选择了数学方法,最短

#include<cstdio>
#include<iostream>
using namespace std;
int read()
{
    int ret=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9')
        ret=(ret<<1)+(ret<<3)+ch-'0',
        ch=getchar();
    return ret;
}
 
int ans;
 
int main()
{
    int T=read();
    while(T--)
    {
        int u=read(),v=read();
        if(v>=u) 
        {
            if((v-u)%3==0) printf("%d\n",(v-u)/3);
            if((v-u)%3==2) printf("%d\n",(v-u+4)/3+2);
            if((v-u)%3==1) printf("%d\n",(v-u+2)/3+1);
        } else
        {
            if(!((u-v)&1)) printf("%d\n",(u-v)>>1);
                else printf("%d\n",((u+3-v)>>1)+1);
        }
    }
    return 0;
}

B

时间限制: 1 Sec  内存限制: 128 MB

题目描述

 有一个N*M的迷宫,每个格子是空地或者障碍,现在从一个起点出发,共有2中操作。

1、沿着上、下、左、右4个方向走到相邻的空地上,时间是1

2、沿着上下左右4个方向,跨越障碍,跳到最近的空地上,时间是2

问,从起点到终点最少的时间。如果不能到达输出-1

 

输入

多组数据,第一行一个整数T(1<=T<=10) 

第一行两个整数N和M(1<=N,M<=50),表示地图的大小

接下来N行,每行M个字符,仅包含两种字符“.”和“#”,分别表示空地和障碍

接下来4个整数r1、c1、r2、c2,表示起点和终点的行列。

起点终点保证唯一,且都是空地。

输出

 从起点到终点最少时间。

样例输入

2 4 4 .##. .### .### .... 0 0 3 3 2 2 #. .# 0 1 1 0

样例输出

4 -1

 

宽搜,深搜剪枝,构图跑Dijkstra,SPFA……

忘了初始化堆了。。(我怎么这么菜

#include<cstdio>
#include<queue>
using namespace std;
int read()
{
    int ret=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9')
        ret=(ret<<1)+(ret<<3)+ch-'0',
        ch=getchar();
    return ret;
}
 
int n,m,cnt;
const int N=105,M=1e6+5;
char s[N];
bool a[N][N],fl[M];
int he[M],w[M],to[M],nxt[M],dis[M];
 
inline int id(int i,int j)
{
    return (i-1)*m+j;
}
 
struct NA{
    int id,x;
};
 
bool operator >(NA i,NA j)
{
    return i.x>j.x;
}
 
priority_queue<NA,vector<NA>,greater<NA> >q;
 
inline void add(int u,int v,int k)
{
    w[++cnt]=k;
    to[cnt]=v;
    nxt[cnt]=he[u];
    he[u]=cnt;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)
                a[i][j]=s[j]=='.'?0:1;
        }
        for(int i=0;i<=id(n,m);i++) 
            he[i]=0;
        cnt=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(!a[i][j])
                {
                    if(i!=1&&!a[i-1][j]) 
                        add(id(i,j),id(i-1,j),1);
                    if(i!=n&&!a[i+1][j])
                        add(id(i,j),id(i+1,j),1);
                    if(j!=1&&!a[i][j-1])
                        add(id(i,j),id(i,j-1),1);
                    if(j!=m&&!a[i][j+1])
                        add(id(i,j),id(i,j+1),1);
                    int t;
                    for(t=i-1;t>=1;t--)
                        if(!a[t][j]) break;
                    if(t>0&&t!=i-1&&!a[t][j])
                        add(id(i,j),id(t,j),2);
                    for(t=i+1;t<=n;t++)
                        if(!a[t][j]) break;
                    if(t<=n&&t!=i+1&&!a[t][j])
                        add(id(i,j),id(t,j),2);
                    for(t=j-1;t>=1;t--)
                        if(!a[i][t]) break;
                    if(t>0&&t!=j-1&&!a[i][t])
                        add(id(i,j),id(i,t),2);
                    for(t=j+1;t<=m;t++)
                        if(!a[i][t]) break;
                    if(t<=m&&t!=j+1&&!a[i][t])
                        add(id(i,j),id(i,t),2); 
                }
        int x=read()+1,y=read()+1;
        int xx=read()+1,yy=read()+1;
        for(int i=1;i<=id(n,m);i++) 
            dis[i]=2e9,fl[i]=0;
        while(!q.empty()) q.pop();
        q.push((NA){id(x,y),dis[id(x,y)]=0});
        for(int i=1;i<=id(n,m);i++)
        {
            while(!q.empty()&&fl[q.top().id]) q.pop();
            if(q.empty()) break;
            int u=q.top().id;
            if(u==id(xx,yy)) break;
            q.pop();
            fl[u]=1;
            for(int e=he[u];e;e=nxt[e])
            {
                int v=to[e];
                if(!fl[v]&&dis[v]>dis[u]+w[e]) 
                    q.push((NA){v,dis[v]=dis[u]+w[e]});
            }
        }
        if(dis[id(xx,yy)]==2e9) dis[id(xx,yy)]=-1;
        printf("%d\n",dis[id(xx,yy)]);
    }
    return 0;
}

C

时间限制: 1 Sec  内存限制: 128 MB

题目描述

 我们称一个序列A中的某一个数为重数,当且仅当该数在序列中出现的次数超过序列长度的一半。

例如:序列{1,2,1}中,1就是重数。而在序列{1,2,3}和{1,2,1,3}中都不存在重数。

现在给定一个包含n个元素的序列A,每个元素为整数,范围在[0,m-1]。你的任务是统计出包含重数的子区间共有多少个。

由于出题人不想生成大文件。。。输入数据有3个整数构成,分别为n,seed和m。出题人告诉你用如下方法生成数据:

for i = 0 .. n-1:
A[i] = (seed div 2^16) modulo m
seed = (seed * 1103515245 + 12345) modulo 2^31

其中:div表示整除;^表示乘幂;modulo 表示取模

输入

 三个整数n(1<=n<=10^5), seed(0<=seed<=2^31-1), m(1<=m<=50)

输出

输出生成的序列中,包含重数的子区间数量

样例输入

5 200 5 10 15 3 8 12345678 1

样例输出

8 23 36

提示

 

 【样例1解释】

 

A = {0, 0, 1, 2, 0},包含1个元素的子区间有5个

 

剩下三个分别为{0, 0}、{0, 0, 1}、{0, 0, 1, 2, 0}.

 

设b【i】【j】表示前i个数中值为j的个数

则题目变成求(l,r),使2(b[r][j]-b[l-1][j])>r-(l-1)的个数

移项得:2b[r][j]-r>2b[l-1][j]-(l-1)

固定右端点,树状数组维护一下即可

mmp,考场上想到了,还剩5分钟,啊……

#include<cstdio>
#define ll long long
using namespace std;
  
int n,see,m;
const int N=1e5+5;
int a[N],b[N][51],c[(N<<2)+1][51];
ll ans;
  
inline void add(int bj,int x)
{
    for(int i=x;i<=(n<<2);i+=i&-i) c[i][bj]++;
}
  
inline int getsum(int bj,int x)
{
    int ret=0;
    for(int i=x;i;i-=i&-i) ret+=c[i][bj];
    return ret;
}
int main()
{
    scanf("%d%d%d",&n,&see,&m);
    for(int i=1;i<=n;i++)
    {
        a[i]=(see/(1<<16))%m+1;
        see=((ll)see*1103515245+12345)%(1<<31);
    }
      
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            b[i][j]=b[i-1][j];
            if(a[i]==j) b[i][j]++;
        }   
         
    ans=0;
    int INF=n+1;
    for(int j=1;j<=m;j++)
        add(j,INF);
         
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            ans+=getsum(j,(b[i][j]<<1)-i-1+INF),
            add(j,(b[i][j]<<1)-i+INF);
        }
    printf("%lld\n",ans);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值