20170515测试

问题 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
",map[i][j]);
56 }
57 int main()
58 {
59     solve();
60     print();
61     return 0;
62 }
View Code

问题 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 2100
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
",sum(c,d)-sum(a-1,d)-sum(c,b-1)+sum(a-1,b-1)); 
62         }
63     } 
64     return 0;
65  } 
View Code

问题 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],l[500005];
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=l[b-a+1];
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=l[b-a+1];
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     for (int i=1;i<=500000;i++)
64         l[i]=log(i)/log(2); 
65     Build();
66     while (m--){
67         int a,b; scanf("%d%d",&a,&b);
68         printf("%d
",Query(a,b));
69     }
70     return 0;
71  } 
View Code

问题 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老题了,代码量有点大,所以,,就不上代码了我不会告诉你们我懒得写。

原文地址:https://www.cnblogs.com/SXia/p/6863626.html