其他分享
首页 > 其他分享> > 2022高考集训2(6.6)

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