问题 A: 棋盘覆盖问题
时间限制: 1 Sec 内存限制: 128 MB
题目描述
在一个2^k×2^k个方格组成的棋盘中恰有一个方格与其它方格不同(图中标记为-1的方格),称之为特殊方格。现用L型(占3个小方格)纸片覆盖棋盘上除特殊方格的所有部分,各纸片不得重叠,于是,用到的纸片数恰好是(4^k-1)/3。在下表给出的一个覆盖方案中,k=2,相同的3各数字构成一个纸片。
下面使用分治法设计的,将棋盘一分为四,依次处理左上角、右上角、左下角、右下角,递归进行。输出最后的棋盘。
输入
输入文件共2行。
第1行: 一个整数k,表示一个2^k×2^k个方格组成的棋盘。
第2行:两个整数,dr,dc,表示坐标为(dr,dc)的方格为特殊方格。
输出
摆放好数字后的,2^k×2^k个方格组成的棋盘
样例输入
2
2 2
样例输出
2 2 3 3
2 -1 1 3
4 1 1 5
4 4 5 5
提示
【数据范围】
50%的数据k<=5。
100%的数据k<=10。
题解:分治,将原问题分为形式相同,规模更小的子问题。
将棋盘分成4份,在中间交界构造出一块纸片,使得每块里均有一个特殊方格。
1 #include <iostream> 2 #include <cstdio> 3 #define N 2100 4 using namespace std; 5 int map[N][N],n,bx,by,cnt; 6 void dfs(int x,int y,int xx,int yy,int k) 7 { 8 if (x+1==xx) 9 { 10 ++cnt; 11 if (k!=1) map[x][y]=cnt; 12 if (k!=2) map[x][yy]=cnt; 13 if (k!=3) map[xx][y]=cnt; 14 if (k!=4) map[xx][yy]=cnt; 15 return; 16 } 17 int ox=(x+xx)>>1,oy=(y+yy)>>1,o=(xx-x+1)>>2,po,temp; 18 if (k==0) 19 { 20 if (bx<=ox && by<=oy) po=1; 21 else if (bx<=ox) po=2; 22 else if (by<=oy) po=3; 23 else po=4; 24 dfs(ox-o+1,oy-o+1,ox+o,oy+o,po); 25 if (po==1) temp=0;else temp=4; 26 dfs(x,y,ox,oy,temp); 27 if (po==2) temp=0;else temp=3; 28 dfs(x,oy+1,ox,yy,temp); 29 if (po==3) temp=0;else temp=2; 30 dfs(ox+1,y,xx,oy,temp); 31 if (po==4) temp=0;else temp=1; 32 dfs(ox+1,oy+1,xx,yy,temp); 33 } 34 else 35 { 36 dfs(ox-o+1,oy-o+1,ox+o,oy+o,k); 37 if (k!=1) dfs(x,y,ox,oy,4); 38 if (k!=2) dfs(x,oy+1,ox,yy,3); 39 if (k!=3) dfs(ox+1,y,xx,oy,2); 40 if (k!=4) dfs(ox+1,oy+1,xx,yy,1); 41 } 42 } 43 void solve() 44 { 45 cin>>n>>bx>>by; 46 n=1<<n; 47 dfs(1,1,n,n,0); 48 } 49 void print() 50 { 51 map[bx][by]=-1; 52 for (int i=1;i<=n;++i) 53 for (int j=1;j<=n;++j) 54 if (j<n) printf("%d ",map[i][j]); 55 else printf("%d\n",map[i][j]); 56 } 57 int main() 58 { 59 solve(); 60 print(); 61 return 0; 62 }
问题 B: 上帝造题的七分钟
时间限制: 1 Sec 内存限制: 128 MB
题目描述
“第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵。
第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作。
第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
第五分钟,和雪说,要有耐心,于是便有了时间限制。
第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造裸题的七分钟》
所以这个神圣的任务就交给你了。
输入
输入数据的第一行为X n m,代表矩阵大小为n×m。
从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
L a b c d delta ——代表将(a,b),(c,d)为顶点的矩形区域内的所有数字加上delta
k a b c d——代表求(a,b),(c,d)为顶点的矩形区域内所有数字的和
请注意,k为小写。
输出
针对每个k操作,在单独的一行输出答案。
样例输入
X 4 4
L 1 1 3 3 2
L 2 2 4 4 1
k 2 2 3 3
样例输出
12
提示
【数据范围】
对于100%的数据,1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, 1 ≤ abs(delta) ≤ 500,操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。
裸题,二维树状数组:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); 33 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 34 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 35 if(last==‘-‘)ans=-ans; return ans; 36 } 37 int n,m; 38 #define N 3000 39 #define lowbit(i) (i&(-i)) 40 int t_1[N][N],t_2[N][N],t_3[N][N],t_4[N][N]; 41 void add(int x,int y,int v_1,int v_2,int v_3,int v_4){ 42 for (int i=x;i<=n;i+=lowbit(i)) 43 for (int j=y;j<=m;j+=lowbit(j)) t_1[i][j]+=v_1,t_2[i][j]+=v_2,t_3[i][j]+=v_3,t_4[i][j]+=v_4; 44 } 45 int sum(int x,int y){ 46 int Sum1=0,Sum2=0,Sum3=0,Sum4=0; 47 for (int i=x;i>0;i-=lowbit(i)) 48 for (int j=y;j>0;j-=lowbit(j)) Sum1+=t_1[i][j],Sum2+=t_2[i][j],Sum3+=t_3[i][j],Sum4+=t_4[i][j]; 49 return Sum1*x*y-Sum2*x-Sum3*y+Sum4; 50 } 51 int main() 52 { 53 char ch[10]; scanf("%s%d%d",ch,&n,&m); 54 while (~scanf("%s",ch)){ 55 if (ch[0]==‘L‘){ 56 int a,b,c,d,v; scanf("%d%d%d%d%d",&a,&b,&c,&d,&v); 57 add(a,b,v,v*(b-1),v*(a-1),v*(a-1)*(b-1)); add(a,d+1,-v,(-v)*d,(-v)*(a-1),(-v)*d*(a-1)); 58 add(c+1,b,-v,(-v)*(b-1),(-v)*c,(-v)*c*(b-1)); add(c+1,d+1,v,v*d,v*c,v*d*c); 59 } else { 60 int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); 61 printf("%d\n",sum(c,d)-sum(a-1,d)-sum(c,b-1)+sum(a-1,b-1)); 62 } 63 } 64 return 0; 65 }
问题 C: 最优贸易简化版
时间限制: 1 Sec 内存限制: 128 MB
题目描述
C国有n座城市,编号是1到n,编号为i的城市有路到编号为i+1的城市(编号为n的城市没有路到其他的城市)。
C国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙再次来到C国旅游。他还是想贩卖水晶赚取旅费,在某个城市买入,再另一个城市卖出。
他将从编号为a的城市到编号到b的城市。请你帮他算算,最多能赚多少钱。
注:他最多进行一次买入和一次卖出。
输入
第一行两个整数n和m,表示n个城市和m个询问。
第二行n个整数,表示n座城市水晶的买入和卖出的价格。
接下来m行,每行两个整数a、b,表示阿龙要从编号为a的城市到编号为b的城市(a<b);
输出
对于每个询问输出阿龙能赚多少钱。
样例输入
6 3
2 1 3 6 4 5
1 2
2 4
1 6
样例输出
0
5
5
提示
【输出输出样例解释】
从1到2,无法赚钱。
从2到4,在编号为2的城市买入,在编号为4的城市卖出。
从1到6,在编号为2的城市买入,在编号为4的城市卖出。
对于20%的数据,n和m的范围[1,500];
对于40%的数据,n和m的范围[1,5000];
【数据范围】
对于20%的数据,n和m的范围[1,500];
对于40%的数据,n和m的范围[1,5000];
对于70%的数据,n和m的范围[1,50000];
对于100%的数据,n和m的范围[1,500000];
类似RMQ问题(可以用ST表解决):
最小买入价格Mi[i][j] = min(Mi[i][j - 1]; Mi[i + 2j-1][j - 1]);
最大卖出价格Mx[i][j] = max(Mx[i][j - 1]; Mx[i + 2j-1][j - 1]);
最大收益F[i][j] = maxfF[i][j - 1]; F[i + 2j-1][j - 1],Mx[i + 2j-1][j - 1] - Mi[i][j - 1];
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); 33 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 34 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 35 if(last==‘-‘)ans=-ans; return ans; 36 } 37 int n,m; 38 int f_a[500005][20],f_i[500005][20],f[500005][20]; 39 void Build(){ 40 for (int i=1;i<=n;i++) { 41 scanf("%d",&f_a[i][0]); f_i[i][0]=f_a[i][0]; f[i][0]=0; 42 } 43 for (int j=1;(1<<j)<n;j++) 44 for (int i=1;i+(1<<j)-1<=n;i++){ 45 f_a[i][j]=max(f_a[i][j-1],f_a[i+(1<<(j-1))][j-1]); 46 f_i[i][j]=min(f_i[i][j-1],f_i[i+(1<<(j-1))][j-1]); 47 f[i][j]=max(max(f[i][j-1],f[i+(1<<(j-1))][j-1]),f_a[i+(1<<(j-1))][j-1]-f_i[i][j-1]); 48 } 49 } 50 int Query_(int a,int b){ 51 if (a>b) return 0; 52 int k=(int)((log(b-a+1)*1.0)/(log(2))); 53 return max(f_a[a][k],f_a[b-(1<<k)+1][k]); 54 } 55 int Query(int a,int b){ 56 if (a>=b) return 0; 57 int k=(int)((log(b-a+1)*1.0)/(log(2))); 58 return max(f[a][k],max(Query(a+(1<<k),b),Query_(a+(1<<k),b)-f_i[a][k])); 59 } 60 int main() 61 { 62 scanf("%d%d",&n,&m); 63 Build(); 64 while (m--){ 65 int a,b; scanf("%d%d",&a,&b); 66 printf("%d\n",Query(a,b)); 67 } 68 return 0; 69 }
问题 D: 维护数列
时间限制: 1 Sec 内存限制: 128 MB
题目描述
输入
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
输出
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
样例输入
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
样例输出
-1
10
1
10
提示
【数据范围】
你可以认为在任何时刻,数列中至少有 1 个数。 输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有 30 000 个数; 100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 个,输入文件 大小不超过 20MBytes。
splay老题了,代码量有点大,所以,,就不上代码了我不会告诉你们我懒得写。