2021 10.12 模拟测试*

T1

Problem

Description

数轴上有 \(n\) 个棋子, 第 \(i\) 个棋子初始在 \(a_i\).

你会不断对棋子进行操作, 每次操作是选择一个棋子, 假设它的坐标是 \(x\), 则可以把它移动到 \(x - 1\)\(x - 2\), 但要求移动后的位置原先没有棋子.

如果一个棋子的坐标变得小于等于 \(0\), 则称它挂掉了. 你需要求出有多少个排列 \(p\) 使得存在一种方案使得第 \(i\) 个挂掉的棋子是 \(p_i\). 答案对 \(10^9 + 7\) 取模.

Task

Input

第一行一个正整数 \(n\).
接下来一行 \(n\) 个正整数 \(a_i\).

Output

一行一个整数表示答案对 \(10^9 + 7\) 取模的结果.

Sample

Input

3
1 2 3

Output

4

Explanation

第 3 个棋子不能最先挂掉.

Constraints

对于所有数据, 保证 \(1 ≤ n ≤ 10^5, 1 ≤ a_1 < a_2 < · · · < a_n ≤ 10^9\).
• 子任务 1(10 分): 保证 \(n ≤ 3, a_i ≤ 10.\)
• 子任务 2(15 分): 保证 \(n ≤ 4, a_i ≤ 10.\)
• 子任务 3(20 分): 保证 \(n ≤ 5, a_i ≤ 10.\)
• 子任务 4(55 分): 无特殊限制.

Solution

对于任意一个数字,假设它前面有\(sum-1\)个数字,如果它满足可以在区间任意时刻跳出序列,那么需要满足在它的至少在第\(2 \times sum-1\)个位置,否则它是不可能跳出去的。
因此,我们可以顺序每一个数字,看它是否满足上述条件,如果无法满足,我们只要在当前序列随机删除一个数字即可(可以移动前面的数字让出通道,所以可以随机删),每删一个数字就有\(sum\)种情况,而这个是满足乘法性质的,所以对于\(ans\)直接乘上\(sum\)即可,最后得到序列则一定是满足全排列的,那么\(ans\)在乘上\(!sum\)就可以了

#include<bits/stdc++.h>
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
const int mod=1e9+7,N=1e5+5;
int n,ans=1,sum,a[N];
inline int add(int a,int b){return a+b>=mod?a+b%mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
int main()
{
	#ifdef socc
	freopen("soc.in","r",stdin);
	#else
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	#endif
	n=in;
	for(int i=1;i<=n;i++)
	{
		sum++;
		a[i]=in;
		if(a[i]<dec(mul(sum,2),1)) ans=mul(ans,sum),sum--;
	}
	for(int i=1;i<=sum;i++) ans=mul(ans,i);
	write(ans);
	return 0;
}

T2

Problem

Description

有一个长度为 \(a + b + c + d + e\)\(01\) 串, 它由 \(a\)\(1\), \(b\)\(0\), \(c\)\(1\), \(d\)\(0\), \(e\)\(1\) 拼接起来组成.

有 m 个区间 \([l_i, r_i]\) 你可以进行若干次操作, 每次操作选择一个区间 \([l_i, r_i]\) 并将\([l_i, r_i]\)取反, 花费的代价为 \(r_i-l_i + 1\).

求将这个串变成全 \(1\) 串的最小代价. 无解输出 \(-1\).

Task

Input

第一行五个正整数 \(a, b, c, d, e.\)
第二行一个正整数 \(m.\)
接下来 \(m\) 行, 每行两个整数 \(l_i, r_i\)

Output

一行一个整数表示答案.

Sample

Input

1 2 3 4 5
3
2 3
2 6
4 10

Output

12

Explanation

操作 \([2, 6]\)\([4, 10]\) 即可

Constraints

对于所有数据, 满足 \(1 ≤ a, b, c, d, e, m ≤ 10^5\), \(1 ≤ l_i < r_i ≤ a + b + c + d + e.\)
• 子任务 1(15 分): 保证 \(m ≤ 10.\)
• 子任务 2(50 分): 保证 \(a, b, c, d, e ≤ 50.\)
• 子任务 3(35 分): 无特殊限制.

Solution

这是一个最短路……
首先我们可以先把这个序列差分,差分后我们可以发现只有四个地方的值是不一样的,而对于每一次操作其实就是将操作区间两端的值互换,所以我们可以从区间右端点向左端点连一条大小为\(r-l+1\)的边,而答案则一定是分别覆盖两个端点的两条最短路,对于那四个点分别跑一个\(spfa\)就可以了。

#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
const int N=5e5+10;
int x1,x2,x3,x4,x5,m,ans=inf;
struct edge{int v,w,nxt;}e[N];
int first[N],cnt;
int f[10][10],dis[N],vis[N];
inline void add(int u,int v,int w){e[++cnt]=(edge){v,w,first[u]};first[u]=cnt;}
void spfa(int s)
{
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	queue<int>q;
	dis[s]=0;vis[s]=1;q.push(s);
	while(!q.empty())
	{
		int u=q.front();q.pop();vis[u]=0;
		for(int i=first[u];i;i=e[i].nxt)
		{
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w)
			{
				dis[v]=dis[u]+e[i].w;
				if(!vis[v]) q.push(v),vis[v]=1;
			}
		}
	}
}
signed main()
{
	#ifdef socc
	freopen("soc.in","r",stdin);
	#else
	//freopen("b.in","r",stdin);
	//freopen("b.out","w",stdout);
	#endif
	x1=in,x2=in,x3=in,x4=in,x5=in,m=in;
	int k1=x1+1,k2=x1+x2+1,k3=x1+x2+x3+1,k4=x1+x2+x3+x4+1;
	for(int i=1;i<=m;++i)
	{
		int l=in,r=in;
		add(l,r+1,r-l+1);
		add(r+1,l,r-l+1);
	}
	spfa(k1);
	f[1][2]=dis[k2];f[1][3]=dis[k3];f[1][4]=dis[k4];
	spfa(k2);
	f[2][3]=dis[k3];f[2][4]=dis[k4];
	spfa(k3);
	f[3][4]=dis[k4];
	ans = min( f[1][2] + f[3][4] , min( f[1][3] + f[2][4] , f[1][4] + f[2][3] ) );
//	cout<<f[1][2]<<'\n'<<f[1][3]<<'\n'<<f[1][4]<<'\n'<<f[2][3]<<'\n'<<f[2][4]<<'\n'<<f[3][4]<<'\n';
	if(ans>=inf) write(-1);
	else write(ans);
	return 0;
}
posted @ 2021-10-14 19:34  Socratize  阅读(62)  评论(0)    收藏  举报