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