记录暑假CF补题时发现的一些有意思的题。
原题地址
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⋅10^5 , 0≤m≤5⋅10^5) — 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 pnpn.
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.
人话翻译: 一串字符串从1到n,给定几对数,当a恰好在b前面一个时,a和b可以交换位置,问n最多能前进到哪个位置。
代码:
这道题看上去很有意思,但实际上只要贪心即可解决。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=3e5+10;
int a[N],n,m;
set<int>se[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
int x,y;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
se[x].insert(y);
}
int ans=0;
int now=n;
for(int i=n-1;i>=1;i--)
{
int flag=1;
for(int j=i+1;j<=now&&flag;j++)
{
if(se[a[i]].find(a[j])==se[a[i]].end())
flag=0;
}
if(flag)
{
ans++;
for(int k=i;k<now;k++)
swap(a[k],a[k+1]);
now--;
}
}
cout<<ans<<endl;
return 0;
}
原题地址
Now Serval is a junior high school student in Japari Middle School, and he is still thrilled on math as before.
As a talented boy in mathematics, he likes to play with numbers. This time, he wants to play with numbers on a rooted tree.
A tree is a connected graph without cycles. A rooted tree has a special vertex called the root. A parent of a node v is the last different from v vertex on the path from the root to the vertex v. Children of vertex v are all nodes for which v is the parent. A vertex is a leaf if it has no children.
The rooted tree Serval owns has n nodes, node 1 is the root. Serval will write some numbers into all nodes of the tree. However, there are some restrictions. Each of the nodes except leaves has an operation max or min written in it, indicating that the number in this node should be equal to the maximum or minimum of all the numbers in its sons, respectively.
Assume that there are k leaves in the tree. Serval wants to put integers 1,2,…,k to the k leaves (each number should be used exactly once). He loves large numbers, so he wants to maximize the number in the root. As his best friend, can you help him?
Input
The first line contains an integer n (2≤n≤3⋅10^5), the size of the tree.
The second line contains n integers, the i-th of them represents the operation in the node i. 0 represents min and 1 represents max. If the node is a leaf, there is still a number of 00 or 11, but you can ignore it.
The third line contains n−1 integers f2,f3,…,fn (1≤fi≤i−1), where fi represents the parent of the node i.
Output
Output one integer — the maximum possible number in the root of the tree.
Examples
input
6
1 0 1 1 0 1
1 2 2 2 2
output
1
input
5
1 0 1 0 1
1 1 1 1
output
4
input
8
1 0 0 1 0 1 1 0
1 1 2 2 3 3 3
output
4
input
9
1 1 0 0 1 0 1 0 1
1 1 2 2 3 3 4 4
output
5
Note
Pictures below explain the examples. The numbers written in the middle of the nodes are their indices, and the numbers written on the top are the numbers written in the nodes.
In the first example, no matter how you arrange the numbers, the answer is 1.
In the second example, no matter how you arrange the numbers, the answer is 4.
In the third example, one of the best solution to achieve 4 is to arrange 4 and 5 to nodes 4 and 5.
In the fourth example, the best solution is to arrange 5 to node 5.
**人话翻译: **给一棵以1为根节点的树,每个节点是它儿子们的值中的最大或最小值,设它有t个叶子节点(无子节点),则将1-t赋值到这些节点上,求1节点所能得到的最大值。
代码:
本题主要是思维难度,在编码上较为简单。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int dp[300030],n,tot=0,c=0,head[300030],f[300030];
//c统计叶子结点数,dp[i]统计第i个节点的值最大为第几大的叶子结点的值。
struct node
{
int to,nxt;
}qq[300030];
void add(int u,int v)//加边
{
qq[++tot].to=v;
qq[tot].nxt=head[u];
head[u]=tot;
}
void dfs(int x)
{
int i;
if(!head[x])//是叶子节点
{
dp[x]=1;c++;
return;
}
for(i=head[x];i;i=qq[i].nxt)
{
dfs(qq[i].to);
}
if(f[x])//最大值
{
dp[x]=dp[qq[head[x]].to];
for(i=head[x];i;i=qq[i].nxt)
dp[x]=min(dp[x],dp[qq[i].to]);
}
else//最小值
{
for(i=head[x];i;i=qq[i].nxt)
dp[x]+=dp[qq[i].to];
}
}
int main()
{
ios::sync_with_stdio(false);
int i,j,t,ans;
cin>>n;
for(i=1;i<=n;i++) cin>>f[i];
for(i=2;i<=n;i++)
{
cin>>t;
add(t,i);
}
dfs(1);
ans=c-dp[1]+1;
cout<<ans<<endl;
return 0;
}
原题地址
Neko is playing with his toys on the backyard of Aki’s house. Aki decided to play a prank on him, by secretly putting catnip into Neko’s toys. Unfortunately, he went overboard and put an entire bag of catnip into the toys…
It took Neko an entire day to turn back to normal. Neko reported to Aki that he saw a lot of weird things, including a trie of all correct bracket sequences of length 2n.
The definition of correct bracket sequence is as follows:
The empty sequence is a correct bracket sequence,
If s is a correct bracket sequence, then (s) is a correct bracket sequence,
If s and t are a correct bracket sequence, then st is also a correct bracket sequence.
For example, the strings “(())”, “()()” form a correct bracket sequence, while “)(” and “((” not.
Aki then came up with an interesting problem: What is the size of the maximum matching (the largest set of edges such that there are no two edges with a common vertex) in this trie? Since the answer can be quite large, print it modulo 10^9+7.
Input
The only line contains a single integer n (1≤n≤1000).
Output
Print exactly one integer — the size of the maximum matching in the trie. Since the answer can be quite large, print it modulo 10^9+7.
Examples
input
1
output
1
input
2
output
3
input
3
output
9
Note
The pictures below illustrate tries in the first two examples (for clarity, the round brackets are replaced with angle brackets). The maximum matching is highlighted with blue.
**人话翻译: **在一个合法序列(“(”的个数不少于“)”的个数)的字典树中,最多有多少条边,使它们没有共同的顶点。
代码:
本题就是一道简单的dp题,然而做题时却半天没想出来,感觉暑期自己的IQ下线了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
ll f[4020][4020];//f[i][j]代表前i个字符中,有j个"("的路径数
const ll p=1000000007;
int main ()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;cin>>n;
f[0][0]=1;
for(int i=1;i<=n*2;i+=1)//直接dp即可
{
for(int j=i/2+i%2;j<=n;j+=1)
{
f[i][j]=f[i-1][j-1]+f[i-1][j];
f[i][j]%=p;
}
}
ll ans=0;
for(int i=n*2-1;i>=1;i-=2)
{
for(int j=1;j<=n;j+=1)
{
ans+=f[i][j];
ans%=p;
}
}
cout<<ans<<endl;
return 0;
}
原题地址
Dora the explorer has decided to use her money after several years of juicy royalties to go shopping. What better place to shop than Nlogonia?
There are n stores numbered from 1 to n in Nlogonia. The i-th of these stores offers a positive integer ai.
Each day among the last m days Dora bought a single integer from some of the stores. The same day, Swiper the fox bought a single integer from all the stores that Dora did not buy an integer from on that day.
Dora considers Swiper to be her rival, and she considers that she beat Swiper on day i if and only if the least common multiple of the numbers she bought on day i is strictly greater than the least common multiple of the numbers that Swiper bought on day i.
The least common multiple (LCM) of a collection of integers is the smallest positive integer that is divisible by all the integers in the collection.
However, Dora forgot the values of ai. Help Dora find out if there are positive integer values of ai such that she beat Swiper on every day. You don’t need to find what are the possible values of ai though.
Note that it is possible for some values of ai to coincide in a solution.
Input
The first line contains integers mm and n (1≤m≤50, 1≤n≤10^4) — the number of days and the number of stores.
After this mm lines follow, the i-th line starts with an integer si (1≤si≤n−1), the number of integers Dora bought on day i, followed by si distinct integers, the indices of the stores where Dora bought an integer on the i-th day. The indices are between 1 and n.
Output
Output must consist of a single line containing “possible” if there exist positive integers ai such that for each day the least common multiple of the integers bought by Dora is strictly greater than the least common multiple of the integers bought by Swiper on that day. Otherwise, print “impossible”.
Note that you don’t have to restore the integers themselves.
Examples
input
2 5
3 1 2 3
3 3 4 5
output
possible
input
10 10
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
output
impossible
Note
In the first sample, a possible choice for the values of the ai is 3,4,3,5,2. On the first day, Dora buys the integers 3,4 and 3, whose LCM is 12, while Swiper buys integers 5 and 2, whose LCM is 10. On the second day, Dora buys 3,5 and 2, whose LCM is 30, and Swiper buys integers 3 and 4, whose LCM is 12.
人话翻译:有 n 个商店,第 i 个商店出售正整数 ai(ai不变);Dora 买了 m 天的东西,第 i 天去了 si 个不同的个商店购买了 si 个数;Dora 的对手 Swiper 在第 i 天去了 Dora 未去的商店购买了 n-si 个数;问在这m天里,是否存在序列a(商定货物序列),使得这 m 天都满足 LCM(Dora购买的数) > LCM(Swiper购买的数);
代码:
虽然看了许多大佬们的解释,但还是只懂了一半。
只要任意两天拿的石头有交集就有解。
稍微看得懂的一个讲解
代码暴力枚举
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 3e5 + 10;
int n,m,tot,p;
int vis[60][maxn];
int main()
{
scanf("%d%d",&m,&n);
for(int i = 1; i <= m; i++)
{
scanf("%d",&tot);
for(int j = 1; j <= tot; j++)
{
scanf("%d",&p);
vis[i][p] = 1;
}
}
for(int i = 1; i <= m; i++)
{
for(int j = i + 1; j <= m; j++)
{
bool f = false;
for(int k = 1; k <= n; k++)
{
if(vis[i][k] == 1 && vis[j][k] == 1)
{
f = true;
break;
}
}
if(!f)
{
puts("impossible");
return 0;
}
}
}
puts("possible");
return 0;
}
原题地址
Nauuo is a girl who loves drawing circles.
One day she has drawn a circle and wanted to draw a tree on it.
The tree is a connected undirected graph consisting of n nodes and n−1 edges. The nodes are numbered from 1 to n.
Nauuo wants to draw a tree on the circle, the nodes of the tree should be in n distinct points on the circle, and the edges should be straight without crossing each other.
“Without crossing each other” means that every two edges have no common point or the only common point is an endpoint of both edges.
Nauuo wants to draw the tree using a permutation of n elements. A permutation of n elements is a sequence of integers p1,p2,…,pn in which every integer from 1 to n appears exactly once.
After a permutation is chosen Nauuo draws the i-th node in the pi-th point on the circle, then draws the edges connecting the nodes.
The tree is given, Nauuo wants to know how many permutations are there so that the tree drawn satisfies the rule (the edges are straight without crossing each other). She only wants to know the answer modulo 998244353, can you help her?
It is obvious that whether a permutation is valid or not does not depend on which n points on the circle are chosen.
Input
The first line contains a single integer n (2≤n≤2⋅10^5) — the number of nodes in the tree.
Each of the next n−1 lines contains two integers u and v (1≤u,v≤n), denoting there is an edge between u and v.
It is guaranteed that the given edges form a tree.
Output
The output contains a single integer — the number of permutations suitable to draw the given tree on a circle satisfying the rule, modulo 998244353.
Examples
input
4
1 2
1 3
2 4
output
16
input
4
1 2
1 3
1 4
output
24
Note
Example 1
All valid permutations and their spanning trees are as follows.
Here is an example of invalid permutation: the edges (1,3) and (2,4) are crossed.
Example 2
Every permutation leads to a valid tree, so the answer is 4!=24.
**人话翻译: **给定n个节点和它们的生成树,将它们排列在一个圆上,使它们的枝不相交,求有多少种排法。
代码:
详细讲解
对1节点(起始节点)单独处理(有n个位置可选),之后对每个节点和它的t个子树(看作一个大节点),有(t+1)!种放法。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
const int maxn=2e5+50;
const int MOD=998244353;
int n;
int num;
int head[maxn];
struct Edge
{
int to,next;
}G[maxn<<1];
void addEdge(int u,int v)
{
G[++num].to=v;
G[num].next=head[u];
head[u]=num;
}
ll fact[maxn];
ll dp[maxn];//dp[i]为i节点及其子树一共有多少放法
vector<int >son[maxn];
void DFS(int u,int f)
{
for(int i=head[u];i;i=G[i].next)
{
int v=G[i].to;
if(v == f)
continue;
son[u].push_back(v);
DFS(v,u);
}
int k=son[u].size()+(u!=1);//1节点单独处理
dp[u]=fact[k];
for(int i=0;i < son[u].size();++i)
dp[u]=dp[u]*dp[son[u][i]]%MOD;
}
ll Solve()
{
for(int i=0;i <= n;++i)
son[i].clear();
DFS(1,1);
return dp[1]*n%MOD;
}
void Init()
{
num=0;
fact[0]=1;
for(int i=1;i <= n;++i)
fact[i]=(i*fact[i-1])%MOD;
}
int main()
{
ll ans;
scanf("%d",&n);
Init();
for(int i=1;i < n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
ans=Solve();
cout<<ans<<endl;
return 0;
}
原题地址
代码:
本题主要是思维难度,根据参考博客的思路,可将此题变为一道纯贪心题。