您的位置:首页 > 大数据 > 人工智能

2016 Multi-University Training Contest 8题解报告

2016-08-11 18:34 543 查看
此文章可以使用目录功能哟↑(点击上方[+])

菜鸡得不行...

2016
Multi-University Training Contest 8官方题解

链接→2016 Multi-University Training Contest 8




 Problem 1001 Ball

Accept: 0    Submit: 0

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)




 Problem Description

ZZX has a sequence of boxes numbered 1,2,...,n. Each box can contain at most one ball.

You are given the initial configuration of the balls. For 1≤i≤n, if the i-th box is empty then a[i]=0, otherwise the i-th box contains exactly one ball, the color of which is a[i], a positive integer. Balls with the same color cannot be distinguished.

He will perform m operations in order. At the i-th operation, he collects all the balls from boxes l[i],l[i]+1,...,r[i]-1,r[i], and then arbitrarily put them back to these boxes. (Note that each box should always contain at most one ball)

He wants to change the configuration of the balls from a[1..n] to b[1..n] (given in the same format as a[1..n]), using these operations. Please tell him whether it is possible to achieve his goal.



 Input

First line contains an integer t. Then t testcases follow.

In each testcase: First line contains two integers n and m. Second line contains a[1],a[2],...,a
. Third line contains b[1],b[2],...,b
. Each of the next m lines contains two integers l[i],r[i].

1<=n<=1000,0<=m<=1000, sum of n over all testcases <=2000, sum of m over all testcases <=2000.

0<=a[i],b[i]<=n.

1<=l[i]<=r[i]<=n.



 Output

For each testcase, print "Yes" or "No" in a line.



 Sample Input

5

4 1

0 0 1 1

0 1 1 1

1 4

4 1

0 0 1 1

0 0 2 2

1 4

4 2

1 0 0 0

0 0 0 1

1 3

3 4

4 2

1 0 0 0

0 0 0 1

3 4

1 3

5 2

1 1 2 2 0

2 2 1 1 0

1 3

2 4



 Sample Output

No

No

Yes

No

Yes



 Problem Idea

解题思路:

【题意】

n个箱子,每个箱子最多放1个球

若第i个箱子是空的,那么a[i]=0

否则,a[i]表示第i个箱子中放有1个a[i]这种颜色的小球

接下来有m次操作,第i次操作可将[l[i],r[i]]区间内所有箱子里的小球拿出来再随机放回到这些箱子中(每个箱子内最多放1个小球)

问,经过m次操作之后,能否到达想要的效果,即第i个箱子里放有b[i]球

【类型】

贪心+排序

【分析】

在解决这个问题之前,必须要了解的一点是

假设能够实现预想的效果的前提下,那么针对于k个颜色相同(它们的a[i]值相同)的球,初始时从左到右标为1,2,3,4,……,k

那么肯定存在一种方案,使得最后结束时红球的顺序没有改变,也是1,2,3,4,……,k

这是为什么呢?显然,可以肯定的是,如果1,2,3,4,……,k->乱序状态可以实现的话,那么1,2,3,4,……,k->1,2,3,4,……,k必定可以实现,反之则不然

如下图所示

①顺序



②乱序



显然,①所涉及的操作区间要比②所涉及的操作范围小得多

好了,理解这点之后,题目就转化成了n个不同颜色的球要从a[i]状态经m次操作到达b[i]状态

如果我们按照最终状态来对每个球进行标号(1,2,3,……,n),那m次操作过程就相当于讲一个乱序数列经过多个区间排序,变成顺序数列

那么对于每次操作,就是贪心的把一个区间排序就行了

【时间复杂度&&优化】

O(n^2logn)

题目链接→HDU 5821 Ball



 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
int a
,b
,cnt
;
vector<int> v
;
int main()
{
int t,n,m,i,l,r,x;
scanf("%d",&t);
while(t--)
{
v[0].clear();
memset(cnt,0,sizeof(cnt));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
cnt[a[i]]++;
v[i].clear();
}
for(i=1;i<=n;i++)
{
scanf("%d",&b[i]);
cnt[b[i]]--;
}
for(i=0;i<=n;i++)
if(cnt[i])
break;
if(i<=n)
{
for(i=0;i<m;i++)
scanf("%d%d",&l,&r);
puts("No");
continue;
}
for(i=1;i<=n;i++)
v[b[i]].push_back(i);
for(i=n;i>0;i--)
{
x=a[i];
a[i]=v[x].back();
v[x].pop_back();
}
for(i=0;i<m;i++)
{
scanf("%d%d",&l,&r);
sort(a+l,a+r+1);
}
for(i=1;i<=n;i++)
if(a[i]!=i)
break;
if(i<=n)
puts("No");
else
puts("Yes");
}
return 0;
}





 Problem 1003 color II

Accept: 0    Submit: 0

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)




 Problem Description

You are given an undirected graph with n vertices numbered 0 through n-1.

Obviously, the vertices have 2^n - 1 non-empty subsets. For a non-empty subset S, we define a proper coloring of S is a way to assign each vertex in S a color, so that no two vertices in S with the same color are directly connected by an edge. Assume we've
used k different kinds of colors in a proper coloring. We define the chromatic number of subset S is the minimum possible k among all the proper colorings of S.

Now your task is to compute the chromatic number of every non-empty subset of the n vertices.



 Input

First line contains an integer t. Then t testcases follow. 

In each testcase: First line contains an integer n. Next n lines each contains a string consisting of '0' and '1'. For 0<=i<=n-1 and 0<=j<=n-1, if the j-th character of the i-th line is '1', then vertices i and j are directly connected by an edge, otherwise
they are not directly connected.

The i-th character of the i-th line is always '0'. The i-th character of the j-th line is always the same as the j-th character of the i-th line.

For all testcases, 1<=n<=18. There are no more than 100 testcases with 1<=n<=10, no more than 3 testcases with 11<=n<=15, and no more than 2 testcases with 16<=n<=18.



 Output

For each testcase, only print an integer as your answer in a line.

This integer is determined as follows:

We define the identity number of a subset S is

. Let the chromatic number of S be

.

You need to output

.



 Sample Input

2

4

0110

1010

1101

0010

4

0111

1010

1101

1010



 Sample Output

1022423354

2538351020

Hint

For the first test case, ans[1..15]= {1, 1, 2, 1, 2, 2, 3, 1, 1, 1, 2, 2, 2, 2, 3}



 Problem Idea

解题思路:

【题意】

给定一个n个结点的图, 

求它的每一个非空子图的最小染色数

(最小染色数的含义为,任何两个直接相连的结点必须是不同颜色,问整个子图需要几种颜色)

输出

的值

其中 n≤18

【类型】

状压dp

【分析】

在解决这个问题之前,需了解一种位运算

int n;
scanf("%d",&n);
for(int i=n;i;i=(i-1)&n)
printf("%d\n",i);


该位运算还是比较神奇的,别看只有与运算参与,它可以算出

二进制数子集的取法,结果不会输出0,且从大到小

比如数6,其二进制表示为110,那它的子集为110(6),100(4),10(2)

再比如数21,二进制为10101,它的子集为10000(16),100(4),1(1),10100(20),10001(17),101(5),10101(21)

好了,言归正传

首先,毋庸置疑,独立集只需一种颜色就可以了,因为独立集内所有的结点都是不相连的

那其他非独立集无非就是独立集的组合

所以,我们先状压表示出所有的子集状态,即每个子集取了哪些结点

然后枚举并记录哪些子集是非独立集,即至少存在一条边相连

然后dp,将每个子集的独立集提取出来并取小值,求出每个子集的答案,代入公式

即可

【时间复杂度&&优化】

O(3^n)

题目链接→HDU 5823 color II



 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1<<18;
const int M = 20;
const int inf = 1000000007;
const int mod = 1000000007;
bool v
;
char s[M][M];
int ans
;
int main()
{
int t,n,i,j,k,all;
unsigned int res,pos;
scanf("%d",&t);
while(t--)
{
res=0;pos=1;
memset(v,false,sizeof(v));
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%s",s[i]);
all=1<<n;
for(i=1;i<all;i++)
{
ans[i]=inf;
for(j=0;j<n&&!v[i];j++)
if((i>>j)&1)
{
for(k=0;k<n&&!v[i];k++)
if((i>>k)&1&&s[j][k]=='1')
v[i]=true;//将非独立集标记为true
}
for(j=i;j;j=(j-1)&i)
if(!v[j])//判断是否为独立集
ans[i]=min(ans[i],ans[i^j]+1);//独立集的贡献为1
res+=ans[i]*(pos*=233);//unsigned int范围为2^32,正好是模数,所以采取unsigned int可以自动帮我们取模
}
printf("%u\n",res);
}
return 0;
}





 Problem 1006 physics

Accept: 0    Submit: 0

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)




 Problem Description

There are n balls on a smooth horizontal straight track. The track can be considered to be a number line. The balls can be considered to be particles with the same mass.

At the beginning, ball i is at position Xi. It has an initial velocity of Vi and is moving in direction Di.(Di∈−1,1)

Given a constant C. At any moment, ball its acceleration Ai and velocity Vi have the same direction, and magically satisfy the equation that Ai * Vi = C.

As there are multiple balls, they may collide with each other during the moving. We suppose all collisions are perfectly elastic collisions.

There are multiple queries. Each query consists of two integers t and k. our task is to find out the k-small velocity of all the balls t seconds after the beginning.

* Perfectly elastic collision : A perfectly elastic collision is defined as one in which there is no loss of kinetic energy in the collision.



 Input

The first line contains an integer T, denoting the number of testcases.

For each testcase, the first line contains two integers n <= 10^5 and C <= 10^9.

n lines follow. The i-th of them contains three integers Vi, Xi, Di. Vi denotes the initial velocity of ball i. Xi denotes the initial position of ball i. Di denotes the direction ball i moves in. 

The next line contains an integer q <= 10^5, denoting the number of queries.

q lines follow. Each line contains two integers t <= 10^9 and 1<=k<=n.

1<=Vi<=10^5,1<=Xi<=10^9



 Output

For each query, print a single line containing the answer with accuracy of 3 decimal digits.



 Sample Input

1

3 7

3 3 1

3 10 -1

2 7 1

3

2 3

1 2

3 3



 Sample Output

6.083

4.796

7.141



 Problem Idea

解题思路:

【题意】

有n个质量相同的球在一维坐标轴上分别从位置xi以初速度vi朝某个方向di运动

任何时刻加速度a与速度v均满足a*v=C(C为已知常数)

在运动过程中,小球发生的碰撞均为完全弹性碰撞

问t时刻,速度第k小的小球的速度为多少

【类型】

物理+积分+排序

【分析】

首先,出题人良心地给了一波完全弹性碰撞

或许你已经忘了这是个什么东西

不要紧,我们只要知道,在完全弹性碰撞下,两质量相同的物体发生碰撞,它们会交换速度

即若小球A和小球B发生碰撞时,小球A速度为v1,小球B速度为v2,那么碰撞之后,小球A速度变为v2,小球B速度变为v1,方向相反

那也就意味着,即便速度发生交换,但是实实在在的那两个速度还是存在的,且大小没有变化,只是换了主人

方便理解,你也可以理解成没有任何事情发生,n个小球互不干扰地各自运动

那问题就转化成求每个小球t时刻的速度(因为速度和加速度都是时刻变化的,所以要求一波积分)

已知,速度=加速度*时间,即


且a*v=C,故



对两边求定积分,可求得t时刻的速度v



由上式可知,在t时刻,速度大小只取决于小球的初速度大小

故该题就被简化成对于每个询问t k

我们只要将初速度第k小的小球数据代入公式计算就可以得到t时刻该小球的速度

因此,我们要将小球按初速度从小到大排个序,那此题就解决了

【时间复杂度&&优化】

O(nlogn)

题目链接→HDU 5826 physics



 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
struct ball
{
int v,x,d;
}s
;
bool cmp(ball x,ball y)
{
return x.v<y.v;
}
int main()
{
int T,n,C,i,q,t,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&C);
for(i=0;i<n;i++)
scanf("%d%d%d",&s[i].v,&s[i].x,&s[i].d);
sort(s,s+n,cmp);
scanf("%d",&q);
for(i=0;i<q;i++)
{
scanf("%d%d",&t,&k);
printf("%.3f\n",sqrt(1.0*s[k-1].v*s[k-1].v+2.0*C*t));
}
}
return 0;
}





 Problem 1008 Rikka with Sequence

Accept: 0    Submit: 0

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)




 Problem Description

As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has an array A with n numbers. Then he makes m operations on it.

There are three type of operations:

1 l r x : For each i in [l,r], change A[i] to A[i]+x

2 l r : For each i in [l,r], change A[i] to 


3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]

It is too difficult for Rikka. Can you help her?



 Input

The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.

For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A
. Then m lines follow, each line describe an operation.

It is guaranteed that 1<=A[i],x<=100000.



 Output

For each operation of type 3, print a lines contains one number -- the answer of the query.



 Sample Input

1

5 5

1 2 3 4 5

1 3 5 2

2 1 4

3 2 4

2 3 5

3 1 5



 Sample Output

5

6



 Problem Idea

解题思路:

【题意】

给你n个数,进行m次操作

操作分为三类:

①1 l r x:将区间[l,r]内的每个元素加上x

②2 l r:将区间[l,r]内的每个元素开根号

③3 l r:输出区间[l,r]内所有元素之和

【类型】

线段树

【分析】

与以往的线段树相比,此题无非就是多了一个区间更新之开根号

相信没有这个开根号操作,肯定大家都会做,毕竟操作①是基本的区间更新

那开根号应该怎么处理呢?开根号操作有两种情况:一种是只有开根号操作;另一种就是本题这种既带有开根号,又有另外的区间操作的题目

①对于只有开根号操作的,例如HDU 4027 Can you answer these queries?

因为数的范围有限,多开几次根号该数就会变成1

所以在每次更新的时候,判断一下这个区间里的所有数相加是否等于区间长度就行了

若相等,就不用再往下更新了

否则,就一直更新到叶子结点

因为每个数开根号的次数并不多,所以在更新的时,可以一直更新到叶子结点。

②但显然本题是无法采取这种方法的,因为就算我开根号到1,我还可以通过区间加法再加上去,那操作次数就多得不要不要的了

所以此题的解法与例题HDU 5634 Rikka with Phi有异曲同工之妙

就像题型①中提到的,一个数开根号到1的次数并不会太多,__int64范围以内的数也就最多开7次,那我们是不是可以记录某个区间内的数是否都相同呢?若一个区间内每个数都相同,那我开根号操作只要对一个数进行操作,区间元素之和就等于操作之后的那个数乘上区间长度,是不是觉得方便了许多?

我们用same值记录区间内相同的数为多少,只要有不相同的数混入其中,same值就为0,这样题目就迎刃而解了

另外据说此题要输入挂才不会TLE,但是我试着不用输入挂又交了一发,正好卡过,加上输入挂就只要一千多毫秒了

很遗憾,此题的数据赛后已更新,这种方法已经被卡,给你带来不便请谅解

上述这种方法在数据更新之后之所以会T,有种很重要的数据,即存在两个数,开根号和加x不断交替进行,永远不会相同(例如8,9,不断开根号、加6)

对于这两个数组成的排列,每次都要更新到叶结点,时间上肯定爆炸

那我们对区间内的数进一步分析,可得三种情况:

区间内所有数相等(这种就是上一种方法中same标记的区间)
区间内极差(Max-Min)大于1
区间内极差(Max-Min)等于1

首先我们对于每个区间维护最大值和最小值

情况1直接进行区间操作,情况2最终会转化成3或者1(开根号之后数只会越来越接近)

而情况3中,当极差等于1时,再次开根号,极差可能相等,问题转化为情况1;或者仍然相差1,此时显然区间所有数减去了相同的值,直接修改区间和

也就是说对于Max==Min+1的情况进行一下特殊处理,其余情况正常处理即可

【时间复杂度&&优化】

原谅我有点不会算开根号操作的复杂度

题目链接→HDU 5828 Rikka with Sequence



 Source Code

AC代码

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
struct tree
{
int left,right;
__int64 val,Max,Min,lazy;
}s[4*N];
int a
;
void get_val(int &ret)
{
int sgn=1;
char c;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
sgn=-1,ret=0;
else
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
ret=ret*10+c-'0';
ret*=sgn;
}
void push_up(int p)
{
s[p].val=s[p*2].val+s[p*2+1].val;
s[p].Max=max(s[p*2].Max,s[p*2+1].Max);
s[p].Min=min(s[p*2].Min,s[p*2+1].Min);
}
void push_down(int p)
{
s[p*2].Max+=s[p].lazy;
s[p*2].Min+=s[p].lazy;
s[p*2].val+=s[p].lazy*(s[p*2].right-s[p*2].left+1);
s[p*2].lazy+=s[p].lazy;
s[p*2+1].Max+=s[p].lazy;
s[p*2+1].Min+=s[p].lazy;
s[p*2+1].val+=s[p].lazy*(s[p*2+1].right-s[p*2+1].left+1);
s[p*2+1].lazy+=s[p].lazy;
s[p].lazy=0;
}
void buildtree(int l,int r,int p)
{
s[p].left=l,s[p].right=r,s[p].lazy=0;
if(l==r)
{
s[p].val=s[p].Max=s[p].Min=a[l];
return ;
}
int mid=(l+r)/2;
buildtree(l,mid,p*2);
buildtree(mid+1,r,p*2+1);
push_up(p);
}
void update_sqrt(int l,int r,int p)
{
if(l<=s[p].left&&s[p].right<=r)
{
if(s[p].Max==s[p].Min)
{
__int64 cur=(__int64)sqrt(s[p].Max);
s[p].lazy-=s[p].Max-cur;
s[p].val=cur*(s[p].right-s[p].left+1);
s[p].Max=s[p].Min=cur;
return ;
}
else if(s[p].Max==s[p].Min+1)
{
__int64 cur1=(__int64)sqrt(s[p].Max);
__int64 cur2=(__int64)sqrt(s[p].Min);
if(cur1!=cur2)
{
s[p].lazy-=s[p].Max-cur1;
s[p].val-=(s[p].Max-cur1)*(s[p].right-s[p].left+1);
s[p].Max=cur1;
s[p].Min=cur2;
return ;
}
}
}
if(s[p].lazy)
push_down(p);
int mid=(s[p].left+s[p].right)/2;
if(r<=mid)
update_sqrt(l,r,p*2);
else if(l>mid)
update_sqrt(l,r,p*2+1);
else
{
update_sqrt(l,mid,p*2);
update_sqrt(mid+1,r,p*2+1);
}
push_up(p);
}
void update_add(int l,int r,__int64 x,int p)
{
if(l==s[p].left&&s[p].right==r)
{
s[p].val+=(s[p].right-s[p].left+1)*x;
s[p].lazy+=x;
s[p].Max+=x;
s[p].Min+=x;
return ;
}
if(s[p].lazy)
push_down(p);
int mid=(s[p].left+s[p].right)/2;
if(r<=mid)
update_add(l,r,x,p*2);
else if(l>mid)
update_add(l,r,x,p*2+1);
else
{
update_add(l,mid,x,p*2);
update_add(mid+1,r,x,p*2+1);
}
push_up(p);
}
__int64 query(int l,int r,int p)
{
if(s[p].left==l&&s[p].right==r)
return s[p].val;
if(s[p].lazy)
push_down(p);
int mid=(s[p].left+s[p].right)/2;
if(r<=mid)
return query(l,r,p*2);
else if(l>mid)
return query(l,r,p*2+1);
else
return query(l,mid,p*2)+query(mid+1,r,p*2+1);
push_up(p);
}
int main()
{
int t,n,m,i,type,l,r,x;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
get_val(a[i]);
buildtree(1,n,1);
for(i=0;i<m;i++)
{
scanf("%d",&type);
if(type==1)
{
scanf("%d%d%d",&l,&r,&x);
update_add(l,r,x,1);
}
else if(type==2)
{
scanf("%d%d",&l,&r);
update_sqrt(l,r,1);
}
else
{
scanf("%d%d",&l,&r);
printf("%I64d\n",query(l,r,1));
}
}
}
return 0;
}


原AC代码,数据更新后TLE

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
struct tree
{
int left,right;
__int64 sum,same,add;
}s[4*N];
int a
;
void get_val(int &ret)
{
int sgn=1;
char c;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
sgn=-1,ret=0;
else
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
ret=ret*10+c-'0';
ret*=sgn;
}
void push_up(int p)
{
s[p].sum=s[p*2].sum+s[p*2+1].sum;
if(s[p*2].same==s[p*2+1].same)
s[p].same=s[p*2].same;
else
s[p].same=0;
}
void push_down1(int p)
{
s[p*2].same=s[p].same;
s[p*2+1].same=s[p].same;
s[p*2].sum=(s[p*2].right-s[p*2].left+1)*s[p].same;
s[p*2+1].sum=(s[p*2+1].right-s[p*2+1].left+1)*s[p].same;
s[p].same=0;
}
void push_down2(int p)
{
s[p*2].add+=s[p].add;
s[p*2+1].add+=s[p].add;
s[p*2].sum+=(s[p*2].right-s[p*2].left+1)*s[p].add;
s[p*2+1].sum+=(s[p*2+1].right-s[p*2+1].left+1)*s[p].add;
if(s[p*2].same)
s[p*2].same+=s[p].add;
if(s[p*2+1].same)
s[p*2+1].same+=s[p].add;
s[p].add=0;
}
void buildtree(int l,int r,int p)
{
s[p].left=l,s[p].right=r,s[p].add=0;
if(l==r)
{
s[p].sum=s[p].same=a[l];
return ;
}
int mid=(l+r)/2;
buildtree(l,mid,p*2);
buildtree(mid+1,r,p*2+1);
push_up(p);
}
void update_sqrt(int l,int r,int p)
{
if(l<=s[p].left&&s[p].right<=r&&s[p].same)
{
s[p].same=(__int64)sqrt(s[p].same);
s[p].sum=s[p].same*(s[p].right-s[p].left+1);
s[p].add=0;
return ;
}
if(s[p].add)
push_down2(p);
if(s[p].same)
push_down1(p);
int mid=(s[p].left+s[p].right)/2;
if(r<=mid)
update_sqrt(l,r,p*2);
else if(l>mid)
update_sqrt(l,r,p*2+1);
else
{
update_sqrt(l,mid,p*2);
update_sqrt(mid+1,r,p*2+1);
}
push_up(p);
}
void update_add(int l,int r,__int64 x,int p)
{
if(l==s[p].left&&s[p].right==r)
{
s[p].sum+=(s[p].right-s[p].left+1)*x;
if(s[p].same)
s[p].same+=x;
else
s[p].add+=x;
return ;
}
if(s[p].add)
push_down2(p);
if(s[p].same)
push_down1(p);
int mid=(s[p].left+s[p].right)/2;
if(r<=mid)
update_add(l,r,x,p*2);
else if(l>mid)
update_add(l,r,x,p*2+1);
else
{
update_add(l,mid,x,p*2);
update_add(mid+1,r,x,p*2+1);
}
push_up(p);
}
__int64 query(int l,int r,int p)
{
if(s[p].left==l&&s[p].right==r)
return s[p].sum;
if(s[p].add)
push_down2(p);
if(s[p].same)
push_down1(p);
int mid=(s[p].left+s[p].right)/2;
if(r<=mid)
return query(l,r,p*2);
else if(l>mid)
return query(l,r,p*2+1);
else
return query(l,mid,p*2)+query(mid+1,r,p*2+1);
push_up(p);
}
int main()
{
int t,n,m,i,type,l,r,x;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
get_val(a[i]);
buildtree(1,n,1);
for(i=0;i<m;i++)
{
scanf("%d",&type);
if(type==1)
{
scanf("%d%d%d",&l,&r,&x);
update_add(l,r,x,1);
}
else if(type==2)
{
scanf("%d%d",&l,&r);
update_sqrt(l,r,1);
}
else
{
scanf("%d%d",&l,&r);
printf("%I64d\n",query(l,r,1));
}
}
}
return 0;
}





 Problem 1011 Rikka with Parenthesis II

Accept: 0    Submit: 0

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)




 Problem Description

As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Correct parentheses sequences can be defined recursively as follows:

1.The empty string "" is a correct sequence.

2.If "X" and "Y" are correct sequences, then "XY" (the concatenation of X and Y) is a correct sequence.

3.If "X" is a correct sequence, then "(X)" is a correct sequence.

Each correct parentheses sequence can be derived using the above rules.

Examples of correct parentheses sequences include "", "()", "()()()", "(()())", and "(((())))".

Now Yuta has a parentheses sequence S, and he wants Rikka to choose two different position i,j and swap Si,Sj. 

Rikka likes correct parentheses sequence. So she wants to know if she can change S to a correct parentheses sequence after this operation.

It is too difficult for Rikka. Can you help her?



 Input

The first line contains a number t(1<=t<=1000), the number of the testcases. And there are no more then 10 testcases with n>100

For each testcase, the first line contains an integers n(1<=n<=100000), the length of S. And the second line contains a string of length S which only contains ‘(’ and ‘)’.



 Output

For each testcase, print "Yes" or "No" in a line.



 Sample Input

3

4

())(

4

()()

6

)))(((



 Sample Output

Yes

Yes

No

Hint

For the second sample input, Rikka can choose (1,3) or (2,4) to swap. But do nothing is not allowed.



 Problem Idea

解题思路:

【题意】

相信大家应该都知道括号匹配问题

此题就是求解交换某两个位置(不能不交换,且交换次数不能超过1次)的字符之后,整个串括号匹配能否成功

【类型】

栈+特判

【分析】

在解决基础的括号匹配问题时,我们一般都会借助栈stack来帮助我们进行括号匹配

当最终的栈为空就意味着括号匹配成功

但是该题要求恰好交换一次,那我们就需要改一改

对于不交换就匹配成功的串,必须要满足匹配对数>1

例如()(),我们交换1,3两个位置的字符或2,4两个位置的字符,()()->()(),仍然匹配

而()就不能交换了,()->)(,显然交换后不匹配

对于交换前不匹配的串,有几种情况是可以在交换之后匹配成功的

首先,必须满足'('的个数与')'一致,如果这两个数目都不一样,就不提匹配成功了

其次,在能匹配的都匹配完之后,栈内剩2个或4个字符都是可以在交换之后匹配成功的

例如栈内剩)(,交换之后)(->()

栈内剩))((时,交换1,4位置,))((->()()

其他情况就不行了,所以特判这几种情况就可以了

【时间复杂度&&优化】

O(n)

题目链接→HDU 5831 Rikka with Parenthesis II



 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 10005;
const int inf = 1000000007;
const int mod = 1000000007;
stack<char> s;
char a
;
int main()
{
int t,n,i,k,k1,k2;
scanf("%d",&t);
while(t--)
{
k1=k2=k=0;
while(!s.empty())
s.pop();
scanf("%d",&n);
scanf("%s",a);
for(i=0;i<n;i++)
if(a[i]=='(')
s.push('('),k1++;
else
{
k2++;
if(!s.empty()&&s.top()=='(')
s.pop(),k++;
else
s.push(')');
}
if(k1==k2&&(s.size()==0&&k>1||s.size()==2||s.size()==4))
puts("Yes");
else
puts("No");
}
}


菜鸟成长记
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: