## T1 rainbow

### subject

[Title Description]

Mr.Raju and one of his extended families are on vacation. They want to enjoy the scenery in the rainbow, but there are some problems.

In their family, if one wants to ride a rainbow, all the people he likes and everyone who likes him must ride on the rainbow together. If a person does not like him and no one likes him, he can ride on the rainbow.

If you are asked to solve this problem, we will provide you with the weight of all the members of your family, as well as the list of people you like, and also give the total weight that rainbow can bear. You need to calculate the maximum number of people that rainbow can carry under the above conditions.

For ease of description, all family members are labeled from 1 to n.

[Input Format]

There are multiple groups of data, each with a blank line between them.

For each group of data, the first behavior integers n(1 < n < 1000) and c(0 < c < 1000),n denotes the total number of family members, c denotes the carrying capacity of rainbows.

The second behavior n number is the weight of 1 to n family members (the weight is a positive integer of less than 1000).

Next, n row, the first number of k[i] per line indicates how many people the I person likes, then the k[i] integer is the number of the person he likes.

When n=0, c=0 is the end of the data. Ensure that the number of data arrays does not exceed 3.

[Output Format]

For each set of data, the maximum number of people who can ride the rainbow at the same time is output. (Don't leave blank lines between each answer you output).

[Input sample]

5 200 50 50 50 50 50 1 2 1 3 0 1 5 1 4 3 200 100 100 100 1 2 1 3 1 1 0 0

[Output sample]

3 0

[Data Scale]

For 20% of the data: n < 8;

For 100% data: n,c < 1000.

### analysis

First use and check sets to integrate each person with his favorite people and calculate their total weight and total number.

Run 01 knapsack again.

### Code

#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> using namespace std; int read() { int num=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); } return num*w; } const int N=1010; int n,C,a[N],b[N],c[N],fa[N],f[N],maxn; int get(int x) { if(fa[x]==x) return x; return fa[x]=get(fa[x]); } int main() { //freopen("rainbow.in","r",stdin); //freopen("rainbow.out","w",stdout); while(1) { n=read(),C=read(),maxn=0; if(n==0&&C==0) break; memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) a[i]=read(),b[i]=0,c[i]=0,fa[i]=i; for(int i=1;i<=n;i++) { int k=read(); for(int j=1;j<=k;j++) { int x=read(); fa[get(i)]=get(x); } } for(int i=1;i<=n;i++) { int temp=get(i); b[temp]+=a[i],c[temp]++; } for(int i=1;i<=n;i++) if(b[i]!=0) for(int j=C;j>=b[i];j--) f[j]=max(f[j],f[j-b[i]]+c[i]); for(int i=0;i<=C;i++) maxn=max(maxn,f[i]); cout<<maxn<<endl; } return 0; }

## T2 Red Cross

### subject

[Title Description]

The passage to the treasure house was opened, down a long staircase and through a low tunnel, you and Xiao Coco finally came to the door of the treasure house. Then comes the last challenge. If you can open the door of the treasury, the treasure in it will be yours.

The door of the treasure house is still opened by the organ. This door is very strange. It is a square, divided into many small squares with square squares of equal size. These squares are not red or white, and it seems that these squares form many red cross symbols. According to the treasure map, if you find the largest Red Cross on the door and press the square in its center, the door of the treasure house will open.

The Red Cross sign is also a square, with a side length of (2k+1)*(2k+1), where k is a non negative integer. Its four edges are parallel to the edge of the door and consist of (2k+1)*(2k+1) small squares on the door. Here, the Red Cross logo is white as the background color and red as the cross color. Suppose that 1 is red and 0 is white. For the data processed by the computer, except that the median column and the median row are all 1, the other squares are all 0.

The following are several different sizes of signs:

1*1:

1

3*3

010

111

010

5*5

00100

00100

11111

00100

00100

Small cocoa is hard to come by this organ. Now it's up to you. Please help him find the biggest Red Cross sign on this door and export its side length.

[Input Format]

The amount of input is huge. The following input methods are recommended:

scanf("%d\n", &n);

for (i = 1; i<= n; i++) scanf("%s", s[i] + 1);

for (i = 1; i<= n; i++)

for (j = 1; j <= n; j++)

a[i][j] = s[i][j] - '0';

Where n i s the edge length of the door of the treasury, s is an array of characters, and a[i][j] is the value of column J in line I.

[Output Format]

Output a line for each query to indicate the answer.

[Input sample]

5 00011 01011 11100 01001 00010

[Output sample]

3

[Data Scale]

For 30% of the data, n is less than 100.

For 50% of the data, n is less than 500.

For 100% data, n < 2000.

### analysis

Record the values of the submatrices with sum.

For the matrix with (x,y) as the center and length k, if it is Red Cross, then the matrix with (x,y) as the center and length K-2 (k >= 3) must also be Red Cross.

So we can enumerate the center of the Red Cross and find out the length of the largest Red Cross centered on (x,y), which can be realized by dichotomy.

### Code

#include<bits/stdc++.h> using namespace std; const int N=2005; int n,a[N][N],sum[N][N],ans; char s[N][N]; int dfs(int lx,int ly,int rx,int ry) { return sum[rx][ry]+sum[lx-1][ly-1]-sum[lx-1][ry]-sum[rx][ly-1]; } int main() { scanf("%d\n",&n); for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=s[i][j]-'0',sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i][j]) { int l=1,r=min(min(i,j),min(n-i+1,n-j+1)),cnt=1; while(l<=r) { int mid=(l+r)>>1; if(dfs(i-mid+1,j,i+mid-1,j)==mid*2-1&&dfs(i,j-mid+1,i,j+mid-1)==mid*2-1&&dfs(i-mid+1,j-mid+1,i+mid-1,j+mid-1)==mid*4-3) l=mid+1,cnt=mid; else r=mid-1; } ans=max(ans,cnt*2-1); } printf("%d",ans); return 0; }

## T3 histogram

### subject

[Title Description]

In statistics, histogram is a graphical language used to describe the frequency of events. It is a zigzag polygon, which can be seen as some rectangular arrangement. The bottom edges of these rectangles are the same unit length, but they have different heights. For a given rectangle, some arrangement will make the polygon reach the longest circumference. Your task is to find out the longest perimeter and the total number of possible permutations that make up the longest perimeter.

In Figure (a), the heights of the rectangles that make up the polygon are {1, 2, 3, 4} and their circumferences are 16 unit lengths. In Figure (b), the heights of the rectangles that make up the polygon are {3, 1, 2, 4} and their circumferences are 20 unit lengths.

[Input Format]

The input file contains multiple sets of data.

The first behavior of each set of data is an integer n (2 < n < 15), which describes how many rectangles there are in total. The second action is n integers, representing the height of n rectangles.

When n=0, the input data ends. Ensure that the number of data arrays does not exceed 16.

[Output Format]

For each set of data, an integer is output to represent the answer.

[Input sample]

4 1 2 3 4 3 2 6 5 0

[Output sample]

20 8 24 2

[Data Scale]

### analysis

It's not difficult to find that the problem is in full order.

### Code

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline int read() { int num=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); } return num*w; } int n,a[100],ans=0,tot,f[100]; long long sum; int main() { n=read(),f[0]=1; for(int i=1;i<=10;i++) f[i]=f[i-1]*i; while(n) { tot=n*2,ans=0; for(int i=1;i<=n;i++) a[i]=read(),tot+=a[i]*2; sort(a+1,a+1+n); if(n%2==1) { for(int i=1;i<=(n-1)/2;i++) ans+=a[i]*4; sum=f[n/2+1]*f[n/2]; } else { for(int i=1;i<=n/2-1;i++) ans+=a[i]*4; ans+=a[n/2]*2,sum=f[n/2-1]*f[n/2]*n; } cout<<tot-ans<<" "<<sum<<endl; n=read(); } return 0; }

## T4 longest common subsequence

### subject

[Title Description]

Given two sequences A and B of length 5n. Guarantee that the number of N from 1 to n occurs five times in A and B respectively. Find the longest common subsequence of A and B.

[Input Format]

The first line has a positive integer n.

The next two lines, each with 5n positive integers, represent sequences A and B.

[Output Format]

Output an integer, the longest common subsequence length.

[Input sample]

2 1 1 2 2 1 1 2 1 2 2 1 2 2 2 1 1 2 2 1 1

[Output sample]

7

[Data Scale]

For 30% of the data, n < 10.

For 60% of the data, n is less than 1000.

For 100% data, n < 20000.

### analysis

Here's a question from the author.

Note that the n numbers of 1-n appear five times in A and B respectively.

Enumerate I and maintain the longest common subsequence of f[j] representing A[1...i] and B[1...j], ending with B[j].

For each x, all positions of X in B are stored in a two-dimensional array, and all positions of A[i] in B are enumerated.

At this point, all f[j] are the longest common subsequences of A[1...i-1] and B[1...j].

Let g[k]=max(f[1]~f[k-1])+1, that is, g[k] be the longest common subsequence of A[1...i] and B[1...k].

If B[j]!=A[i], then g[j]=f[j], that is, f[j], does not change.

So we only need to make a single point modification and find the maximum prefix, which can be maintained by tree array.

### Code

#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <cmath> using namespace std; inline int read() { int num=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); } return num; } const int N=2e4+5; int n,a[N*5],b[N*5],c[N*5],d[9]; vector<int> g[N*5]; void change(int x,int y) { for(int i=x;i<=n*5;i+=i&-i) c[i]=max(c[i],y); } int ask(int x) { int ans=0; for(int i=x;i;i-=i&-i) ans=max(ans,c[i]); return ans; } int main() { n=read(); for(int i=1;i<=n*5;i++) a[i]=read(); for(int i=1;i<=n*5;i++) b[i]=read(),g[b[i]].push_back(i); for(int i=1;i<=n*5;i++) { for(int j=0;j<=4;j++) { int x=g[a[i]][j]; d[j]=ask(x-1); } for(int j=0;j<=4;j++) { int x=g[a[i]][j]; change(x,d[j]+1); } } cout<<ask(n*5); return 0; }