1. 程式人生 > >topcoder div 2 (1)

topcoder div 2 (1)

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;
}