Description
Arkady invited Anna for a dinner to a sushi restaurant. The restaurant is a bit unusual: it offers n pieces of sushi aligned in a row, and a customer has to choose a continuous subsegment of these sushi to buy.
The pieces of sushi are of two types: either with tuna or with eel. Let’s denote the type of the i-th from the left sushi as ti, where ti=1 means it is with tuna, and ti=2 means it is with eel.
Arkady does not like tuna, Anna does not like eel. Arkady wants to choose such a continuous subsegment of sushi that it has equal number of sushi of each type and each half of the subsegment has only sushi of one type. For example, subsegment [2,2,2,1,1,1] is valid, but subsegment [1,2,1,2,1,2] is not, because both halves contain both types of sushi.
Find the length of the longest continuous subsegment of sushi Arkady can buy.
Input
The first line contains a single integer n (2≤n≤100000) — the number of pieces of sushi.
The second line contains n integers t1, t2, …, tn (ti=1, denoting a sushi with tuna or ti=2, denoting a sushi with eel), representing the types of sushi from left to right.
It is guaranteed that there is at least one piece of sushi of each type. Note that it means that there is at least one valid continuous segment.
Output
Print a single integer — the maximum length of a valid continuous segment.
Examples
input
7
2 2 2 1 1 2 2
output
4
input
6
1 2 1 2 1 2
output
2
input
9
2 2 1 1 1 2 2 2 2
output
6
Note
In the first example Arkady can choose the subsegment [2,2,1,1] or the subsegment [1,1,2,2] with length 4.
In the second example there is no way but to choose one of the subsegments [2,1] or [1,2] with length 2.
In the third example Arkady’s best choice is the subsegment [1,1,1,2,2,2].
题意:找一个最长子串,里面前一半是1,后一半是2,或者前一半是2,后一半是1
做法:sum1表示在第i个字符之前最长的连续1的个数,sum2表示在第i个字符之前最长的连续的2的个数,遍历字符串。当前字符和前一个不一样,如果当前是1,就sum1变为1,如果当前是2,就sum2变为2,ans = max(ans,min(sum1,sum2)),如果当前字符和前一个一样,如果当前是1,就sum1++,如果当前是2,就sum2++。
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 100005;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
int flag = 0,sum1 = 1,sum2 = 1,ans = 0;
for(int i=2; i<=n; i++)
{
if(a[i] == a[i-1])
{
if(a[i] == 2)
{
sum2++;
}
if(a[i] == 1)
{
sum1++;
}
}
if(a[i] != a[i-1])
{
if(a[i] == 2)
{
ans = max(ans,min(sum1,sum2));
sum2 = 1;
}
if(a[i] == 1)
{
ans = max(ans,min(sum1,sum2));
sum1 = 1;
}
}
}
ans = max(ans,min(sum1,sum2));
printf("%d",ans*2);
}
Description
题意:给定一个原矩阵和一个目标矩阵,原矩阵可以通过子矩阵的行列互换进行变换,问是否可以经过多次操作变成目标矩阵。
做法:行列互换,意味着元素是以主对角线为对称轴进行交换,那么我们可以存储原矩阵中主对角线两边有哪些元素,看目标矩阵的所有元素能否在原矩阵的主对角线两边找到。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
const int maxn = 505;
int a[maxn][maxn],b[maxn][maxn];
map<int,int> k[maxn*2];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
scanf("%d",&a[i][j]);
k[i+j+1][a[i][j]]++;//存储主对角线两边的元素
}
}
int flag = 1;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
scanf("%d",&b[i][j]);
if(k[i+j+1][b[i][j]] <= 0)
flag = 0;
k[i+j+1][b[i][j]]--;
}
}
if(flag)
printf("YES");
else
printf("NO");
}
Description
At the big break Nastya came to the school dining room. There are n pupils in the school, numbered from 1 to n. Unfortunately, Nastya came pretty late, so that all pupils had already stood in the queue, i.e. Nastya took the last place in the queue. Of course, it’s a little bit sad for Nastya, but she is not going to despond because some pupils in the queue can agree to change places with some other pupils.
Formally, there are some pairs u, v such that if the pupil with number u stands directly in front of the pupil with number v, Nastya can ask them and they will change places.
Nastya asks you to find the maximal number of places in queue she can move forward.
Input
The first line contains two integers n and m (1≤n≤3⋅105, 0≤m≤5⋅105) — the number of pupils in the queue and number of pairs of pupils such that the first one agrees to change places with the second one if the first is directly in front of the second.
The second line contains n integers p1, p2, …, pn — the initial arrangement of pupils in the queue, from the queue start to its end (1≤pi≤n, p is a permutation of integers from 1 to n). In other words, pi is the number of the pupil who stands on the i-th position in the queue.
The i-th of the following m lines contains two integers ui, vi (1≤ui,vi≤n,ui≠vi), denoting that the pupil with number ui agrees to change places with the pupil with number vi if ui is directly in front of vi. It is guaranteed that if i≠j, than vi≠vj or ui≠uj. Note that it is possible that in some pairs both pupils agree to change places with each other.
Nastya is the last person in the queue, i.e. the pupil with number pn.
Output
Print a single integer — the number of places in queue she can move forward.
Examples
input
2 1
1 2
1 2
output
1
input
3 3
3 1 2
1 2
3 1
3 2
output
2
input
5 2
3 1 5 4 2
5 2
5 4
output
1
Note
In the first example Nastya can just change places with the first pupil in the queue.
Optimal sequence of changes in the second example is
change places for pupils with numbers 1 and 3.
change places for pupils with numbers 3 and 2.
change places for pupils with numbers 1 and 2.
The queue looks like [3,1,2], then [1,3,2], then [1,2,3], and finally [2,1,3] after these operations.
题意:有n个点,m种可以把点进行交换的方法,当且仅当a,b点相邻(题面有个directly in front of 相邻且位于前面的意思),且a在b前面时,a,b才能交换,现在问最后一个点最前能往前几个点。
做法:num[x]数组表示以x为起点,后面能有多少个点和它交换,ans表示最后一个点向前进了几格,当num[x]与最后一个点的距离相等时,表明最后一个点一定可以移到x的位置。num数组怎么获得呢?显然,如果从前面开始遍历数组去得到num数组,那么时间复杂度n方,和暴力枚举并没有什么不同。我们可以每次从后面的点开始去填这个num数组。在遍历数组前,我们先把最后一个点可能可以交换的点的num先++,然后从倒数第二个数开始遍历数组,如果num[x] == n - i - ans(ans初始为0),那么ans++,否则,这个点可能交换到前面的点的num要++。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <set>
using namespace std;
const int maxn = 500005;
int a[maxn],num[maxn];
vector<int>v[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
v[y].push_back(x);
}
for(int i=0; i<v[a[n]].size(); i++)
{
num[v[a[n]][i]]++;
}
int ans = 0;
for(int i=n-1; i>=1; i--)
{
if(num[a[i]] == n-i-ans)
ans++;
else
{
for(int j=0; j<v[a[i]].size(); j++)
{
num[v[a[i]][j]]++;
}
}
}
printf("%d",ans);
}
Description
Polycarp is a head of a circus troupe. There are n — an even number — artists in the troupe. It is known whether the i-th artist can perform as a clown (if yes, then ci=1, otherwise ci=0), and whether they can perform as an acrobat (if yes, then ai=1, otherwise ai=0).
Split the artists into two performances in such a way that:
each artist plays in exactly one performance,
the number of artists in the two performances is equal (i.e. equal to n2),
the number of artists that can perform as clowns in the first performance is the same as the number of artists that can perform as acrobats in the second performance.
Input
The first line contains a single integer n (2≤n≤5000, n is even) — the number of artists in the troupe.
The second line contains n digits c1c2…cn, the i-th of which is equal to 1 if the i-th artist can perform as a clown, and 0 otherwise.
The third line contains n digits a1a2…an, the i-th of which is equal to 1, if the i-th artist can perform as an acrobat, and 0 otherwise.
Output
Print n2 distinct integers — the indices of the artists that should play in the first performance.
If there are multiple answers, print any.
If there is no solution, print a single integer −1.
Examples
input
4
0011
0101
output
1 4
input
6
000000
111111
output
-1
input
4
0011
1100
output
4 3
input
8
00100101
01111100
output
1 2 3 6
Note
In the first example, one of the possible divisions into two performances is as follows: in the first performance artists 1 and 4 should take part. Then the number of artists in the first performance who can perform as clowns is equal to 1. And the number of artists in the second performance who can perform as acrobats is 1 as well.
In the second example, the division is not possible.
In the third example, one of the possible divisions is as follows: in the first performance artists 3 and 4 should take part. Then in the first performance there are 2 artists who can perform as clowns. And the number of artists in the second performance who can perform as acrobats is 2 as well.
题意:给出n个人,一个ci数列,ci为1,代表这个人可以演小丑,ci为0,代表不可以;一个ai数列,ai为1,代表这个人可以演、耍杂技,为0代表不行。现在要选n/2(n为偶数)个人参加第一天的演出,剩下的人参加第二天的演出。他们必须满足下列条件:
1.每个人必须且只能参加一天的演出
2.两天演出的人数一样
3.第一天可以演小丑的人 == 第二天可以耍杂技的人
做法:一开始以为是一题可以推出O(n)做法的思维题,推半天没推出些啥,看了题解才知道原来是个暴力枚举题。(告诉我们要好好斟酌数据范围,n最大为5000,暗示暴力了)。每个人有4种状态,00,01,10,11,我们分别用n1,n2,n3,n4代表每种状态的总人数。a1,a2,a3,a4代表第一天的人中四种状态的人数,我们可以枚举a3,a4,由此b4就可以用n4 - a4推出,b2可以用a3 + a4 - b4 推出,b2要满足大于等于0,小于等于n2,那么a2可以用n2 - b2推出,a1可以由n/2 - a2 - a3 - a4推出。a1要满足大于等于0,小于等于n1。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <set>
#include <cstring>
using namespace std;
const int maxn = 6000;
char s1[maxn],s2[maxn];
int c[maxn],a[maxn];
int main()
{
int n;
scanf("%d",&n);
scanf("%s",s1);
scanf("%s",s2);
for(int i=0; i<strlen(s1); i++)
{
c[i+1] = s1[i] - '0';
}
for(int i=0; i<strlen(s2); i++)
{
a[i+1] = s2[i] - '0';
}
int n1,n2,n3,n4;
n1 = n2 = n3 = n4 = 0;
for(int i=1; i<=n; i++)
{
if(c[i] == 0 && a[i] == 0)
n1++;
if(c[i] == 0 && a[i] == 1)
n2++;
if(c[i] == 1 && a[i] == 0)
n3++;
if(c[i] == 1 && a[i] == 1)
n4++;
}
int a1,a2,b1,b2,b3,b4,flag = 0;
int ans1,ans2,ans3,ans4;
for(int a3=0; a3<=n3; a3++)
{
for(int a4=0; a4<=n4; a4++)
{
b4 = n4 - a4;
b2 = a3 + a4 - b4;
if(b2 < 0 || b2 > n2)
continue;
a2 = n2 - b2;
a1 = n/2 - a2 - a3 - a4;
if(a1 < 0 || a1 > n1)
continue;
ans1 = a1;
ans2 = a2;
ans3 = a3;
ans4 = a4;
flag = 1;
break;
}
if(flag)
break;
}
if(!flag)
printf("-1");
else
{
for(int i=1; i<=n; i++)
{
if(c[i] == 0 && a[i] == 0 && ans1)
{
printf("%d ",i);
ans1--;
}
if(c[i] == 0 && a[i] == 1 && ans2)
{
printf("%d ",i);
ans2--;
}
if(c[i] == 1 && a[i] == 0 && ans3)
{
printf("%d ",i);
ans3--;
}
if(c[i] == 1 && a[i] == 1 && ans4)
{
printf("%d ",i);
ans4--;
}
}
}
}