目录
A. CQXYM Count Permutations
Problem - A - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1581/problem/A题意:给你一个n然后求有几个2n的全排列是满足条件的,条件:一个排列数组中的p(i)< p(i + 1)中的i的数量是大于n的。
思路:已知有2n个元素,那么一共有(2*n)!种排列方式,这些排列方式都是对称的,对于所以符合题目要求的大于n的和小于等于n的根据对称性应该是数量一样的,那我们就除一个2就可以了:
即为(2*n)!/2.因为要取模,不能直接做除法,我们可以化简,就变成了从3一直乘到2n
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=1000000007;
void solve()
{
int n,ans=1;
cin>>n;
n*=2;
for(int i=n;i>=3;i--)
{
ans=ans*i%mod;
}
cout<<ans<<"\n";
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
B. Diameter of Graph
Problem - B - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1581/problem/B题意:给你n,m,k,n个点,m条边,要求n个点用m条边任意苏荷相连,问任意两边的最大距离严格小于k-1的情况是否存在.
思路:我们只需要确定输出YES的情况即可.我们要组成图,一定要有m>=n-1条边.最大的情况就是,每两个点之间互相连线(但是因为不能重复,所以用n*(n-1)之后还要除2),当m==n*(n-1)/2的时候任意两点的最长长度都是1.求出k的范围是否合法即可.当m在[ n-1 , n*(n-1)/2 )这个区间时,可以至少组成一个每两点之间距离最大是2的图:
在这个范围最大值始终为2,判断k的值即可.
当然还有n=1的时候进行1特判.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
void solve()
{
int n ,m ,k;
cin>>n>>m>>k;
if(n==1&&m==0&&k>=2)
{
cout<<"YES\n";
return ;
}
if(n-1<=m&&m<(n-1)*(1+n-1)/2&&k>=4)
{
cout<<"YES\n";
return ;
}
if((n-1)*(1+n-1)/2==m&&k>=3)
{
cout<<"YES\n";
return ;
}
cout<<"NO\n";
return;
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
C. Portal
Problem - C - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1581/problem/C题意:给你一个01矩阵(1为黑曜石砖,0为空气),在最小的01转换操作下(每一次把0变成1,把1变成0)存在一个高a>=5,宽b>=4的末地传送门(四条边都是黑曜石砖(即为1),四个角无所谓,可以为0也可以为1).问最小操作数.
思路:直接进行二维前缀和,看中间区域和边区域需要转换的个数,枚举端点,巨鹿需要转换的最小个数即可.但是n^4肯定会t,所以我们进行一个剪枝qwq;剪枝操作我在代码里写注释.
#include<bits/stdc++.h>
using namespace std;
char ma[504][504];
int sum[504][504];
int query(int cx, int cy, int zx, int zy)
{
return sum[zx][zy]-sum[cx-1][zy]-sum[zx][cy-1]+sum[cx-1][cy-1];
}
void solve()
{
int n,m,ans=1e9;
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%s",ma[i]+1);
memset(sum,0,sizeof sum);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(ma[i][j]-'0');
for(int i=1;i+4<=n;i++)
{
for(int j=1;j+3<=m;j++)
{
for(int k=i+4;k<=n;k++)
{
for(int l=j+3;l<=m;l++)
{
int zhongjian=query(i+1,j+1,k-1,l-1);
int h1=k-i-1-query(i+1,j,k-1,j);
int h2=l-j-1-query(i,j+1,i,l-1);
int l1=k-i-1-query(i+1,l,k-1,l);
int l2=l-j-1-query(k,j+1,k,l-1);
int tt=h1+h2+l1+l2+zhongjian;
if(tt-l1>ans)
break;
//我们已经确定了三条边了,现在在枚举第四条边,当我不算第四条边的时候,
已经大于我所记录的最小值,那么再加上枚举的第四条边,肯定也是大于记录的
最小值,所以继续枚举无意义,直接break;
ans=min(ans,tt);
}
}
}
}
cout<<ans<<"\n";
return ;
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}