比赛记录contest13

本文解析了多个编程竞赛题目,包括天平平衡判断、资金流转优化、构造7的倍数、寻找最大全黑子矩阵等,提供了详细的算法思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛记录contest13

比赛链接

A

Problem description

就是说给你一个字符串,描述了一个天平,然后要求输出这个天平的平衡情况。

Solution

仔细分析一下,这个题就是强行枚举,先从左往右扫,找到支点,然后左右两边分别计算力矩,比下大小,恶心的是要开long long,因此WA了一发,可见数据范围的重要性

using namespace std;
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
char s[20000001];
int l;
int it;
long long le=0,ri=0;
long long ll=0,rl=0;
int main()
{
    scanf("%s",s);
    int l=strlen(s);
    for(int i=0;i<l;i++){if(s[i]=='^') {it=i;break;}}
    ll=0;rl=0;le=ri=0;
    for(int i=it-1;i>=0;i--)
    {
        ll++;
        if(s[i]>='0'&&s[i]<='9')
        {
            le+=(s[i]-'0')*ll;
        }
    }
    for(int i=it+1;i<l;i++)
    {
        rl++;
        if(s[i]>='0'&&s[i]<='9')
        {
            ri+=(s[i]-'0')*rl;
        }
    }
    if(le==ri){puts("balance");return 0;}
    if(le<ri){puts("right");return 0;}puts("left");
}

B

Problem description

就是说给告诉你很多如下的关系:A欠B x元,然后让你找到一种替代方案使得每个人应得的钱没有变。该方案钱流通的最少

Solution

这道题是一道贪心题,只要计算每个人的入账和出账,因为只要每个人应得或应付的钱不变就可以了,所以我们就直接把每个人结算完后应得多少,应付多少算出,应得的人
应得钱的总和即为答案,这样做一定不能再优化,且一定最优。

using namespace std;
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 101
#define ll long long
ll A[201];
ll n,m,a,b,c;
long long res;
int main()
{
    cin>>n>>m;
    memset(A,0,sizeof(A));
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b>>c;
        A[a]-=c;A[b]+=c;
    }
    for(int i=1;i<=n;i++)
    {
        if(A[i]>0) res+=A[i];
    }
    cout<<res;
}

C

Problem description

给你一个数,你可以任意调换数字的顺序且这个数一定含有1, 6, 8, 9,使最后的数为7的倍数,输出最后的数,若没有就输出0。

Solution

把1、6、8、9放在数列的最前端,因为1689的全排列能构成7的剩余系,所以先是利用一位位mod 7取得系数,全排列一发如果可行就输出。
以后遇到这种构造题要观察数据的性质,先尝试暴力一发,再做。

using namespace std;
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
int mod[1000001];
char s[2000001];
int it[2000001];
int yu[7];
int num[7];
int res;
bool vis[10];
int ans;
bool cmp(int x,int y) 
{
    return x>y;
}
int main()
{
    mod[1]=1;
    for(int i=2;i<=1000000;i++) mod[i]=(mod[i-1]*10)%7;
    scanf("%s",s);
    int l=strlen(s);
    for(int i=0;i<l;i++)it[i+1]=s[i]-'0';
    sort(it+1,it+l+1);
//  cout<<l<<endl;
    for(int i=1;i<=l-4;i++)
    {
        if(!vis[1]&&it[i]==1) {swap(it[l-3],it[i]);vis[1]=1;}
        if(!vis[6]&&it[i]==6) {swap(it[l-2],it[i]);vis[6]=1;}
        if(!vis[8]&&it[i]==8) {swap(it[l-1],it[i]);vis[8]=1;}
        if(!vis[9]&&it[i]==9) {swap(it[l],it[i]);vis[9]=1;}
    }
    for(int i=1;i<=l-4;i++) res=(res+it[i]*mod[i])%7;
    ans=res;
    while(next_permutation(it+l-3,it+l+1))
    {
        ans=res;
        for(int i=l-3;i<=l;i++) ans=(ans+it[i]*mod[i])%7;
        if(ans==0)
        {for(int i=l;i>=1;i--)printf("%d",it[i]);return 0;} 
    }
    puts("0");
}

D

Problem description

给你一个有一些黑格的矩阵,你可以任意换矩阵的行和列,然后求这个矩阵中能存在的最大全黑子矩阵的面积

Solution

这道题用到了常用的矩阵中枚举开始点,再+贪心\DP的方法,然后顺序枚举加hash 这么做可以利用前面节点的信息转移方便
具体实现:倒序枚举起始格,计算该格开始,最长长度为x的个数,这样子每次可以O(n)转移,O(m)计算,这种可以快速前推后的可以用这种方法。

using namespace std;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define N 5002
int a[N][N];
int hash[N];
int k[N];
int n,m;
int ans=0;
char s[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        for(int j=1;j<=m;j++) a[i][j]=s[j-1]-'0';
    }
    for(int i=m;i>=1;i--)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[j][i]==1) {k[j]++;hash[k[j]-1]--;hash[k[j]]++;}
            else{hash[k[j]]--;k[j]=0;hash[0]++;}
        }
        int cnt=0;
        for(int j=m;j>=1;j--)
        {
            cnt+=hash[j];
            ans=max(ans,cnt*j);
        }
    }
    cout<<ans<<endl;
}

赛后补题

E

Problem description

就是给你一个矩阵,给你一个开始点,你每次只能走到相邻的可行格。
不可行格有:
1、宝藏
2、炸弹
3、墙
要求你走可行格,最后回到出发点,围成的图形内部不包含炸弹且宝藏权值和减路径长度最大(可以不动)

Solution

围豆豆加强版,炸弹只需要当成一个权值负无限大的豆豆就可以了。
主要思想:判断一个点在一个平面图形内的方法:从这个点射出一条射线,交这个图形如果奇数次则在内部否则在外部,很好证:每穿一次,都会从内、外两种状态
调换,最后是外,利用奇偶性可知原本图形内外。
这道围豆豆利用这个思想,但为了防止特殊情况,必须规定单一的射线穿的方向,具体实现是取min。每次预处理就是给一列上的都打上标记。

using namespace std;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define N 5002
int a[N][N];
int hash[N];
int k[N];
int n,m;
int ans=0;
char s[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        for(int j=1;j<=m;j++) a[i][j]=s[j-1]-'0';
    }
    for(int i=m;i>=1;i--)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[j][i]==1) {k[j]++;hash[k[j]-1]--;hash[k[j]]++;}
            else{hash[k[j]]--;k[j]=0;hash[0]++;}
        }
        int cnt=0;
        for(int j=m;j>=1;j--)
        {
            cnt+=hash[j];
            ans=max(ans,cnt*j);
        }
    }
    cout<<ans<<endl;
}

F

Problem description

给你一棵有根树,每个节点有一个颜色,m次询问,询问以x为根的子树中,有多少种节点个数超过k个的颜色?

Solution

这题可以用dfs序转区间+莫队算法实现,维护后缀和,第一次打莫队,其分块复杂度正确的原因:是
1、块内操作,显然是O(根号n)的。
2、块与块之间之间的操作,以后的块一定不包括中间的块了,所以最后还是O(n根号n)的复杂度。
排序是按左端点块号第一关键字,右端点第二关键字排序。
dfs序转区间这是常用方法,就是搜子树前和搜子树后这段区间,显然是对的。
nlogn^2的算法就是启发式合并,两个map还没来得及写,找到重儿子然后一个个并给他就可以了。

using namespace std;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define N 5002
int a[N][N];
int hash[N];
int k[N];
int n,m;
int ans=0;
char s[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        for(int j=1;j<=m;j++) a[i][j]=s[j-1]-'0';
    }
    for(int i=m;i>=1;i--)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[j][i]==1) {k[j]++;hash[k[j]-1]--;hash[k[j]]++;}
            else{hash[k[j]]--;k[j]=0;hash[0]++;}
        }
        int cnt=0;
        for(int j=m;j>=1;j--)
        {
            cnt+=hash[j];
            ans=max(ans,cnt*j);
        }
    }
    cout<<ans<<endl;
}

G

Problem description

一颗有黑白染色的树,若任意一个节点总有在k距离内有一个黑色节点则称该树美丽,你每次可以换任意两个节点的颜色,求满足要求的最小次数,否则输-1.

Solution

待补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值