A.CQXYM Count Permutations
题意:
1~2n的数字(不重复)序列的排列组合一共会有 ( 2 n ) ! 种不同的结果。
问在这些结果中,正序下标的数量不少于n的有多少个?结果对109+7取模。
正序下标:如果有下标 i 使得a[i]<a[i+1],则称 i 为正序下标。
思路:
2n个数全排列一共种情况,因为是全排列,具有对称性!所以满足条件的排列情况恰好是一半,也就是。把2约掉====
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000000+7;
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
ll ans=1;
for(ll i=3;i<=n*2;i++)
ans=ans*i%mod;
cout<<ans<<endl;
}
}
B.Diameter of Graph
题意:
CQXYM想要创建一个有n个节点和m条边的连通无向图,图的直径必须严格小于k-1。且每条边连接两个不同的顶点,并且每对顶点之间最多有一条边。问是否存在这样一个图。
思路:
1.n个结点与 m 条边无法构成一张图
2.,是个完全图,则图的直径为1,则即可。
这里还需要考虑n=1的情况,只有一个顶点,直径为0,k>1即可。
4.时,图的直径最小,这应该以一个结点为中心,其他结点应该以这个结点为圆心分别与之直接相连,此时图的直径为2。则只需满足 k > 3 即可。
5.时 ,则可以在上图的基础上连接其他的结点,但是图的直径不会大于2。但由于不是完全图,则图的直径大于1。则只需满足 k > 3 即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e5+10;
int main()
{
ll t,n,m,k;
cin>>t;
while(t--)
{
cin>>n>>m>>k;
ll tmp=n*(n-1)/2;
if(m<n-1)
cout<<"NO"<<endl;
else if(m>tmp)
cout<<"NO"<<endl;
else if(m==tmp)
{
if(n==1)
{
if(k>1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
else
{
if(k>2)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
else
{
if(k>3)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
}
C.Portal
题意:
给你一个n*m的零一矩阵,你可以将1变成0,将0变成1,你要从中找到一个子矩阵(传送门)满足:
1.高度大于等于5,宽度大于等于4
2.四条边(除四个顶点)都是1
4.中间部分全是0
输出使矩阵存在一个满足要求的传送门的最小操作次数。
思路:
矩阵n<400,m<400,枚举四条边超时,优化一下枚举三条边O(n^3)。
假设枚举的三条直线,现在要找到最优的直线让这四条直线围起来作为传送门的四条边,满足操作次数最少。
二维矩阵前缀和
枚举传送门的左上角和右下角点,然后计算需要改变的数量。
int val(int x1,int y1,int x2,int y2)
{
int k=num[x2][y2]-num[x1-1][y2]-num[x2][y1-1]+num[x1-1][y1-1];
return k;
}
当D从5到6,新增一行,用上一次最优秀的上部边界,先判度b[D-1][L],b[D-1][R]是否为1,不是要翻转一次,还有该行的中间部分。与以D=6为底部,D-4为顶部围成的矩阵的代价取最小。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e5+10;
char a[500][500];
int b[500][500];
int num[500][500];
int val(int x1,int y1,int x2,int y2)
{
int k=num[x2][y2]-num[x1-1][y2]-num[x2][y1-1]+num[x1-1][y1-1];
return k;
}
int main()
{
int t,n,m;
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
if(a[i][j]=='0')
b[i][j]=0;
else
b[i][j]=1;
}
}
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
num[i][j]=num[i-1][j]+num[i][j-1]-num[i-1][j-1]+b[i][j];
}
}
int ans=INT_MAX;
for(int L=1;L<=m;L++)
{
for(int R=L+3;R<=m;R++)
{
int tmp=n*m;
for(int D=5;D<=n;D++)
{
if(b[D-1][L]==0)
tmp++;
if(b[D-1][R]==0)
tmp++;
tmp+=val(D-1,L+1,D-1,R-1);
int now=(R-L-1)-val(D-4,L+1,D-4,R-1)+3-val(D-3,L,D-1,L)+3-val(D-3,R,D-1,R)+val(D-3,L+1,D-1,R-1);
tmp=min(tmp,now);
ans=min(ans,tmp+((R-L-1)-val(D,L+1,D,R-1)));
}
}
}
cout<<ans<<endl;
}
}