2022高考集训2(6.6)
作者:互联网
每一道题都很有思维含量!
A(交通)
观察此题性质,发现在同一个点的两条 入边(出边)中 如果一条被删,那么剩下的一条必须被保留。
我们的目标是去找环,选择化边为点,在边上建边,那么我们找到有n个环,就有2n种情况。
在具体实现时,我们可以用并查集来维护是否在同一个环中。
Code moo~~
#include<bits/stdc++.h>
#define Bessie moo~~
#define int long long
using namespace std;
int read(){
int A=0,fl=1;
char C=getchar();
while(C<'0'||C>'9')fl= C=='-' ? -1 : 1, C=getchar();
while(C>='0'&&C<='9')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return A*fl;
}
const int MOD=998244353,N=1e5+5;
//找有多少个环
//每个点只能被访问一次
int n,ans;
struct edge{
int from,to;
}e[N<<1];
int f[N<<1];
int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
int In[N<<1][3],Out[N<<1][3];
int qpow(int x,int y){
int base=1;
while(y){
if(y&1)base=base*x%MOD;
x=x*x%MOD;
y>>=1;
}
return base;
}
signed main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
n=read();
for(int i=1,u,v;i<=n*2;i++){
u=read(),v=read();
e[i].from=u;
e[i].to=v;
In[u][++In[u][0]]=i;
Out[v][++Out[v][0]]=i;
f[i]=i;
}
for(int i=1,fx,fy;i<=n;i++){
fx=find(In[i][1]);
fy=find(In[i][2]);
if(fx==fy)ans++;
else f[fy]=fx;
fx=find(Out[i][1]);
fy=find(Out[i][2]);
if(fx==fy)ans++;
else f[fy]=fx;
}
printf("%lld\n",qpow(2,ans));
return 0;
}
B(冒泡排序)
经分析可以得出两个特判
1.当 a[i]==i 时判无解:因为根据题意我们每相邻的两个位置都要交换(仅换一次),现在a[i]已经就位,如果交换那么它永远也换不回来了。
2.当逆序对个数不为(n-1)时判无解:仅换一次。
那么现在这个序列只有了两种情况:
1.a[i]>i:此时我们要将a[i] 从 第i个位置 向右交换到 第a[i]个位置 ,于是我们就可以发现相邻位置的交换顺序有一些限制:形如某对相邻的交换必须在它旁边的相邻对交换之前/之后。
2.a[i]<i:此时也会出现上述限制。
于是我们就把这个问题转换为:有(n-1)个 形如 bi>bi-1 or bi<bi-1 的限制,求满足这些限制的排列b的个数。
考虑DP求解:细节看代码。
Code moo~~
#include<bits/stdc++.h>
#define Bessie moo~~
#define int long long
using namespace std;
int read(){
int A=0,fl=1;
char C=getchar();
while(C<'0'||C>'9')fl= C=='-' ? -1 : 1, C=getchar();
while(C>='0'&&C<='9')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return A*fl;
}
const int MOD=1e9+7;
int n,cnt,ans;
int a[5005];
int vis[5005];
int f[5005],g[5005];
char s[5005];
signed main(){
freopen("mp.in","r",stdin);
freopen("mp.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
a[i]++;
if(a[i]==i){//特判一
printf("0\n");
return 0;
}
}
for(int i=1;i<=n;i++){//特判二 逆序对
for(int j=i+1;j<=n;j++){
if(a[j]<a[i])cnt++;
}
}
if(cnt!=n-1){
printf("0\n");
return 0;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[j]==i){//这个点要向后换
for(int k=i;k<j;k++){
if(vis[k]){//题目规定每一对相邻的两个数只能交换一次
printf("0\n");
return 0;
}
vis[k]=1;
s[k]='>';
}
if(i>1)s[i-1]='<';//首先换这个点,否则不会达到题目要求
break;
}
}
}
// for(int i=1;i<=n;i++){
// printf("%lld %c ",a[i],s[a[i]]);
// }
// for(int i=1;i<=n;i++){
// printf("%c",s[i]);
// }
//前方高能
n--;//交换 n-1 次
f[1]=1;
for(int i=2;i<=n;i++){
memset(g,0,sizeof(g));
if(s[i-1]=='<'){//如果是小于 说明我们要往前挪
for(int j=1;j<=i;j++){
g[j]=(g[j-1]+f[j-1])%MOD;//这里的g[],f[]其实是一个滚动数组,g[]为这一行,f[]为上一行
}
}
else {
for(int j=i;j;j--){
g[j]=(g[j+1]+f[j])%MOD;
}
}
memcpy(f,g,sizeof(g));
}
for(int i=1;i<=n;i++){
ans=(ans+f[i])%MOD;
// printf(" * %lld \n",f[i]);
}
printf("\n%lld\n",ans);
return 0;
}
C(矩阵)
我的做法非常非常却又正常——%大样例。
思路非常简单,大样例怎么做,咱就怎么做。
其实就是将样例消矩阵的步骤模拟出来,再将每次操作完的矩阵打印出来找规律。
此题还有个结论:如果这个矩阵的前两行、前两列都为0,那么这个矩阵就全为零,否则无解。
这个结论在机房中没有讨论出来个结果,有一个大体的思路:应该和高斯消元有关......先咕着
Code moo~~
#include<bits/stdc++.h>
#define Bessie moo~~
#define int long long
using namespace std;
int read(){
int A=0,fl=1;
char C=getchar();
while(C<'0'||C>'9')fl= C=='-' ? -1 : 1, C=getchar();
while(C>='0'&&C<='9')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return A*fl;
}
int n,m;
int a[1005][1005];
int hang[1005],lie[1005],dui[3005];
signed main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
}
}
hang[1]=a[2][2]-a[1][1];
for(int j=1;j<=m;j++)a[1][j]+=hang[1];
for(int i=3;i<=n;i++){
hang[i]=a[i-1][1]-a[i][2];
for(int j=1;j<=m;j++)a[i][j]+=hang[i];
}
for(int j=3;j<=m;j++){
lie[j]=a[1][j-1]-a[2][j];
for(int i=1;i<=n;i++)a[i][j]+=lie[j];
}
for(int i=1;i<=m;i++){
dui[i]=-a[1][i];
for(int t=1;t<=n&&i+t-1<=m;t++){
a[t][i+t-1]+=dui[i];
}
}
for(int i=2;i<=n;i++){
dui[m+i-1]=-a[i][1];
for(int t=1;t<=m&&t+i-1<=n;t++){
a[t+i-1][t]+=dui[m+i-1];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]){
printf("-1\n");
return 0;
}
}
}
printf("%lld\n",n+n+m+m-1);
for(int i=1;i<=n;i++){
printf("1 %lld %lld\n",i,hang[i]);
}
for(int i=1;i<=m;i++){
printf("2 %lld %lld\n",i,lie[i]);
}
for(int i=1;i<=m;i++){
printf("3 %lld %lld\n",i-1,dui[i]);
}
for(int i=2;i<=n;i++){
printf("3 %lld %lld\n",1-i,dui[m+i-1]);
}
return 0;
}
D(花瓶)
还没改出来,咕着。
标签:int,long,6.6,while,moo,2022,define,集训,getchar 来源: https://www.cnblogs.com/Creator-157/p/16349411.html