数据保证:
- 最初的数在进行操作时不会超过long long范围
- 如果你的程序合法,那么运算中所有的数均为整数,所有的除法均为整除!
- 不会出现整数被0除的情况
只需要用一下STL里面的stack就可以了,签到题,没什么难度
#include
#include
using namespace std;
struct p{
int choice;
int x;
};
stack s;
int main()
{
long long int ans;
int n;
cin>>n>>ans;
while(n--)
{
struct p temp;
cin>>temp.choice>>temp.x;
s.push(temp);
}
while(!s.empty())
{
struct p temp=s.top();
s.pop();
switch(temp.choice)
{
case 1:ans-=temp.x;break;
case 2:ans+=temp.x;break;
case 3:ans/=temp.x;break;
case 4:ans*=temp.x;break;
}
}
cout<
2、小a与204
题目描述
小a非常喜欢204这个数字,因为′a′+′k′=204现在他有一个长度为n的序列,其中只含有2,0,4这三种数字设ai为序列中第i个数,你需要重新排列这个数列,使得∑(ai−ai−1)^2最大(公式的含义是:每个数与前一个数差的平方的和)
注意:我们默认a0=0
输入描述:
第一行一个整数n接下来一行n个整数,第i个数表示ai
输出描述:
输出一个整数,表示∑(ai−ai−1)^2的最大值
示例1
输入
2
2 4
输出
20
示例2
输入
3
2 0 4
输出
36
示例3
输入
5
2 4 0 2 4
输出
52
备注:
1⩽n⩽105
保证ai为2/0/4中的数
用了一个比较笨的办法,先排序,再根据一小一大交替,这样能保证和最大,猜测有简便方法,因为只有2、0、4这三个数这个条件没用上,可能是根据这三个数的个数有简便方法
#include
#include
using namespace std;
int num[100005];
int main()
{
int n;
cin>>n;
num[0]=0;
for(int i=1;i<=n;i++)
cin>>num[i];
sort(num,num+n+1);
int max=n;
int min=0;
int cnt=0;
int ans=0;
while(1)
{
if(max==min)break;
ans+=(num[max]-num[min])*(num[max]-num[min]);
if(cnt%2==0) min++;
else max--;
cnt++;
}
cout<
3、小a的轰炸游戏
题目描述
小a正在玩一款即时战略游戏,现在他要用航空母舰对敌方阵地进行轰炸
地方阵地可以看做是n×m的矩形航空母舰总共会派出q架飞机。
飞机有两种,第一种飞机会轰炸以(xi,yi)为中心,对角线长为li的正菱形(也就是两条对角线分别于x轴 y轴平行的正方形),而第二种飞机只会轰炸正菱形的上半部分(包括第xi行)
(具体看样例解释)
现在小a想知道所有格子被轰炸次数的异或和
注意:不保证被轰炸的格子一定在矩形范围内,若越界请忽略
输入描述:
第一行三个整数n,m,q,分别表示矩阵的长/宽/询问次数
接下来q行,每行四个整数opt,x,y,l,表示飞机类型,轰炸的坐标,以及对角线长度
保证l为奇数!
输出描述:
一个整数,表示所有格子被轰炸次数的异或和
示例1
输入:
4 5 4
1 2 2 1
1 3 3 5
1 3 2 3
2 2 4 3
输出:
2
参考答案用的是二维差分,原谅我技术不够从来没听说过这种方法,用的笨办法,超时,过了一半,5000+人一个AC的都没有,果然难,实在想不出还有什么可以继续优化的地方了,先挂一个过了一半超时的代码
#include
#include
int Map[1010][1010];
int n,m;
int main()
{
int q;
scanf("%d %d %d",&n,&m,&q);
memset(Map,0,sizeof(Map));
while(q--)
{
int opt,x,y,l;
scanf("%d %d %d %d",&opt,&x,&y,&l);
x--;y--;
if(opt==1)
{
int tx=x;
if(tx<0)tx=0;
for(int i=l;i>=1;i-=2)
{
int j=y-i/2;
if(j<0)j=0;
for(;j<=y+i/2&&j=n)break;
tx=x+1;
for(int i=l-2;i>=1;i-=2)
{
int j=y-i/2;
if(j<0)j=0;
for(;j<=y+i/2&&j=n)break;
}
}
else
{
int tx=x;
if(tx<0)tx=0;
for(int i=l;i>=1;i-=2)
{
int j=y-i/2;
if(j<0)j=0;
for(;j<=y+i/2&&j=n)break;
}
}
int ans=0;
for(int i=0;i
难点在于怎么确定被轰炸的范围,给的是轰炸的中心坐标和轰炸半径,也就是说要根据这个来确定一个菱形,最简单的情况是轰炸的菱形完全在地图内,这种情况下就通过坐标和半径来确定就可以,每一行差2个点,这样就可以确定,更复杂一点的情况是轰炸区域比地图还要大,这样就需要进行缩小,从轰炸中心的一行往上不断缩小就可以了,菱形的下半部分是对称的,代码不需要有太大改动,用笨办法做只能做到这样,暂时还想不出来哪里还可以优化了,答案的二维差分如下,反正我是看不懂了
#include
#define LL long long
using namespace std;
const int MAXN = 1e6 + 10, MAX = 5001, INF = 1e9 + 10, base = 1201;
void chmin(int &a, int b) {a = (a < b ? a : b);}
void chmax(int &a, int b) {a = (a > b ? a : b);}
int sqr(int x) {return x * x;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, Q, type[MAXN], a[MAX][MAX], opt[MAX][MAX][2], b[MAX][MAX], xx[MAXN], yy[MAXN], ll[MAXN];
void solve1(int x, int y, int len) {
len /= 2;
a[x - len][y]++;
if(len == 0) return ;
opt[x - len + 1][y - 1][0]++;
opt[x - len + 1][y + 2][1]--;
opt[x + 1][y - len - 1][0]--;
opt[x + 1][y + len + 2][1]++;
}
void solve2(int x, int y, int len) {
len /= 2;
if(len == 0) return ;
a[x + len][y]++;
opt[x + len - 1][y - 1][0]++;
opt[x + len - 1][y + 2][1]--;
opt[x][y - len][0]--;
opt[x][y + len + 1][1]++;
}
void print() {
puts("");
for(int i = 0; i <= N + base * 2; i++, puts(""))
for(int j = 0; j <= M + base * 2; j++)
printf("%d ", a[i][j] + b[i][j]);
}
signed main() {
N = read(); M = read(); Q = read();//采用更加快速的读入方式
for(int i = 1; i <= Q; i++)
type[i] = read(), xx[i] = read() + base, yy[i] = read() + base, ll[i] = read();//读入方式坐标半径
for(int i = 1; i <= Q; i++)
solve1(xx[i], yy[i], ll[i]);
for(int i = 0; i <= N + 2 * base; i++) {
int sum = 0;
for(int j = 0; j <= M + 2 * base; j++) {
sum += opt[i][j][0] + opt[i][j][1];
a[i][j] += sum;
opt[i + 1][j - 1][0] += opt[i][j][0];
opt[i + 1][j + 1][1] += opt[i][j][1];
}
}
memcpy(b, a, sizeof(a));
memset(a, 0, sizeof(a));
memset(opt, 0, sizeof(opt));
for(int i = 1; i <= Q; i++)
if(type[i] == 1) solve2(xx[i], yy[i], ll[i]);
for(int i = N + base * 2; i >= 0; i--) {
int sum = 0;
for(int j = 0; j <= M + 2 * base; j++) {
sum += opt[i][j][0] + opt[i][j][1];
a[i][j] += sum;
opt[i - 1][j - 1][0] += opt[i][j][0];
opt[i - 1][j + 1][1] += opt[i][j][1];
}
}
//print();
int ans = 0;
for(int i = 1 + base; i <= N + base; i++)
for(int j = 1 + base; j <= M + base; j++)
ans ^= (a[i][j] + b[i][j]);
cout << ans;
return 0;
}
4、小a的排列
题目描述
小a有一个长度为n的排列。定义一段区间是"萌"的,当且仅当把区间中各个数排序后相邻元素的差为1现在他想知道包含数x,y的长度最小的"萌"区间的左右端点
也就是说,我们需要找到长度最小的区间[l,r],满足区间[l,r]是"萌"的,且同时包含数x和数y如果有多个合法的区间,输出左端点最靠左的方案。
输入描述:
第一行三个整数N,x,y,分别表示序列长度,询问的两个数
第二行有n个整数表示序列内的元素,保证输入为一个排列
输出描述:
输出两个整数,表示长度最小"萌"区间的左右端点
输入
5 2 3
5 2 1 3 4
输出
2 4
输入
8 3 5
6 7 1 8 5 2 4 3
输出
5 8
备注:
保证2⩽n⩽105,1⩽x,y⩽n
考点在于模拟和分析,意思就是说找一个连续序列包含给出的两个数,很像蓝桥杯2013年本科B里面的一道题,但是这一道更难,大体思路就是先找到给你的L和R,之后扩展空间,直到符合连续空间为止,这里补充一点,一般的连续空间问题都要用到公式:max-min=r-l,即区间最大值-区间最小值等于右端点-左端点。具体看官方的代码,自己写的能过25%的数据,因为没有考虑到扩展区间的更优方法。
#include
using namespace std;
const int MAXN = 1e5 + 10, INF = 1e9 + 10;
void chmin(int &a, int b) {a = (a < b ? a : b);}
void chmax(int &a, int b) {a = (a > b ? a : b);}
int N, L, R, a[MAXN], pos[MAXN];
int main() {
cin>>N>>L>>R;
for(int i = 1; i <= N; i++)
cin>>a[i] , pos[a[i]] = i;//数字a[i]的位置在pos[a[i]]的位置
L = pos[L]; R = pos[R];//把L、R换成对应所在的位置
if(L > R) swap(L, R);
int mx = -1, mn = INF, l = L, r = R;
for(int i = L; i <= R; i++) chmin(mn, a[i]), chmax(mx, a[i]);//确定区间最大值和最小值
for(int i = mn; i <= mx; i++) chmin(l, pos[i]), chmax(r, pos[i]);//在最大值和最小值所在区间之间选择左右两端点,保证区间是连续的
while(l < L || R < r){
int tmn = mn, tmx = mx;
while(l < L) chmin(tmn, a[--L]), chmax(tmx, a[L]);//在扩大的区间里找新的最大和最小值
while(R < r) chmin(tmn, a[++R]), chmax(tmx, a[R]);
for(int i = tmn; i <= mn; i++)
chmin(l, pos[i]), chmax(r, pos[i]); //在扩大的区间里找新的左右端点
for(int i = mx; i <= tmx; i++)
chmin(l, pos[i]), chmax(r, pos[i]);
mn = tmn; mx = tmx;
}
cout << l << ' ' << r;
return 0;
}
强烈吐槽官方给的测试用例,情况太少,这里补充一组测试用例
输入:
9 7 4
1 3 6 9 7 5 8 4 2
以这组测试用例为例,需要的L为7,R为4,交换一下后为L=4,R=7,就是说目前区间为{7,5,8,4}这四个数,要想成为连续空间,需要补一个6,在对应的POS数组中查询4-7的位置,从而求出要想使其 变成连续空间,就要把原区间扩展到L=6,R=7,这时候从L到R扩展为{6,9,7,5,8,4},由于扩展了一部分,要重新找区间最大值和区间最小值,再从对应POS数组里找位置,发现这时不需要再扩展空间,此时就说明现在的L-R为要求的萌区间,输出L和R的位置即可。
主要的难点在于怎么扩展区间,连续区间的特点要求要找最小和最大,再找最小和最大对应的位置,在这个新区间中再找最大最小,直到不需要再扩展区间。