第十三届蓝桥杯省赛C/C++ B组

@

A九进制转十进制

答案是1478

B顺子日期

答案14(如果012算的话)

C刷题统计

数据范围1e18,所以不能直接暴力,先取余,再暴力剩下的

#include<bits/stdc++.h>
using namespace std;
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define per(i,m,n) for(int i=m;i>=n;i--)
#define pair<int,int> PII
#define int long long
signed main()
{
    int a,b,n;
    cin>>a>>b>>n;
    int ans=0,cnt=0;
    int x=5*a+2*b;//一周刷题数
    ans=n/x*7;
    n=n%x;
    while(1)
    {
        if(cnt>=n)
            break;
        ans++;
        if(ans%7==0||ans%7==6)
            cnt+=b;
        else
            cnt+=a;
    }
    cout<<ans;
    return 0;
}

D 修剪灌木

先读题
然后结论就是直接取左右两边最大的二倍

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int N=1e4+10;
int a[N];
signed main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int l,r;
        l=(i-1)*2;
        r=(n-i)*2;
        cout<<max(l,r)<<endl;
    }
    return 0;
}

E X进制减法

这个题读了半天才懂,注意他说的进制是指逢几进一,
答案就是每一位取能取的最小进制
在这里插入图片描述
这里面的321=((3*10+2)*2)+1=65
也可以这样算 1+2*2+3*10*2=65

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int mod=1e9+7;
const int N=1e5+10;
int a[N],b[N],c[N],p[N];
signed main()
{
    int k,ma,mb;
    cin>>k>>ma;
    for(int i=ma;i>=1;i--)
        cin>>a[i];
    cin>>mb;
    for(int i=mb;i>=1;i--)
        cin>>b[i];
    int n=max(ma,mb);
    for(int i=1;i<=n;i++)
        c[i]=a[i]-b[i];
    for(int i=n;i>=1;i--)
    {
        int pp=2;
        pp=max(pp,max(a[i],b[i])+1);//最低p进制
        p[i+1]=pp;
    }
    int ans=0;
    for(int i=n;i>=2;i--)
    {
        c[i-1]+=c[i]*p[i];
    }
    cout<<c[1]<<endl;
    return 0;
}

F统计子矩阵

直接暴力的话(n^6) 铁炸!
使用前缀和+暴力的话(n^4) 也会炸
最后一维用二分优化(n^3*log n) 可能会炸,但我想不到更好的了

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int N=5e2+10;
int a[N][N],sum[N][N];
int n,m,K;
int S(int x2,int y2,int x1,int y1)
{
    return sum[x1][y1]-sum[x1][y2-1]-sum[x2-1][y1]+sum[x2-1][y2-1];
}
signed main()
{
    cin>>n>>m>>K;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    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]+a[i][j];
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]>K)continue;
            for(int k=i;k<=n;k++)
            {
                int l=j,r=m;
                while(l<r)
                {
                    int mid=l+r+1>>1;
                    if(S(i,j,k,mid)<=K)l=mid;
                    else r=mid-1;
                }
                if(S(i,j,k,l)>K)continue;
                //printf("%lld %lld %lld %lld\n",i,j,k,l);
                ans+=(l-j+1);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

G 积木画

状态压缩DP
f[i][j]表示已经摆完前i列,且突出来的状态为j
假如j=1:就是凸出来了上面那一块

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int mod=1e9+7;
const int M=1<<2;
const int N=1e7+10;
int f[N][M];
signed main()
{
    int n;
    cin>>n;
    f[0][0]=1;
    for(int i=1;i<=n+1;i++)
    {
        f[i][0]=(f[i][0]+f[i-1][0]+f[i-1][3])%mod;//不突出
        f[i][1]=(f[i][1]+f[i-1][2]+f[i-1][0])%mod;//上面突出
        f[i][2]=(f[i][2]+f[i-1][1]+f[i-1][0])%mod;//下面突出
        f[i][3]=(f[i][3]+f[i-1][0]+f[i-1][1]+f[i-1][2])%mod;//突出两个
    }
    cout<<f[n][0]<<endl;
    return 0;
}

第一维可以用滚动数组优化

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int mod=1e9+7;
const int M=1<<2;
int f[3][M];
signed main()
{
    int n;
    cin>>n;
    f[0][0]=1;
    for(int i=1;i<=n+1;i++)
    {
        f[i&1][0]=(f[i-1&1][0]+f[i-1&1][3])%mod;//不突出
        f[i&1][1]=(f[i-1&1][2]+f[i-1&1][0])%mod;//上面突出
        f[i&1][2]=(f[i-1&1][1]+f[i-1&1][0])%mod;//下面突出
        f[i&1][3]=(f[i-1&1][0]+f[i-1&1][1]+f[i-1&1][2])%mod;//突出两个
    }
    cout<<f[n&1][0]<<endl;
    return 0;
}

H扫雷

直接两重循环建边+dfs搜索的,会炸(因为建边是两重循环,过不叫第二个5e4的样例)
注意不能并查集,因为a引爆b,但b不一定能引爆a
正解应该是看那个r(r<=10),不会....

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int N=1e3+10;
vector<int> q[N];
int x[N],y[N],r[N];
int n,m;
bool vis[N];
bool v[N];
int cnt;
bool check(int x1,int y1,int r1,int x2,int y2)
{
    return (x2-x1)*(x2-x1)+(y2-x1)*(y2-y1)<=r1*r1;//1会引炸2
}
void dfs(int x)
{
    cnt++;
    for(int i=0;i<q[x].size();i++)
    {
        int j=q[x][i];
        if(vis[j]||v[N])continue;
        v[j]=1;
        dfs(j);
    }
}
signed main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i]>>y[i]>>r[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)continue;
            if(check(x[i],y[i],r[i],x[j],y[j]))
            {
                q[i].push_back(j);
            }
        }
    }
    while(m--)
    {
        int xx,yy,rr;
        cin>>xx>>yy>>rr;
        for(int i=1;i<=n;i++)
        {
            if(check(xx,yy,rr,x[i],y[i]))
            {
                vis[i]=1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(vis[i])
            dfs(i);
    }
    cout<<cnt<<endl;
    return 0;
}

I李白打酒加强版

dp,考虑遇到店或者花
f[i][j][k]表示已经走了i次,有j次经过了酒馆,还剩k斗酒
记录酒的时候只需要斗里有100以下的容量 ,因为最多走100次也就是最多喝100斗酒,太多了喝不完

#include<bits/stdc++.h>
using namespace std;
#define pair<int,int> PII
#define int long long
const int mod=1e9+7;
const int N=100+10;
int n,m;
int f[N+N][N+N][N];//f[i][j][k]表示已经走了i次,有j次经过了酒馆,还剩k斗酒
signed main()
{
    cin>>n>>m;
    f[0][0][2]=1;
    for(int i=1;i<=n+m;i++)
    {
        for(int j=0;j<=i;j++)
        {
            for(int k=0;k<100;k++)
            {
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k+1])%mod;
                if(j>=1&&k%2==0)
                    f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k/2])%mod;
            }
        }
    }
    cout<<f[n+m-1][n][1]<<endl;
    return 0;
}

J砍竹子

这个没时间写了,随便写的

posted @ 2022-04-09 20:01  巴扎嘿~  阅读(1379)  评论(6编辑  收藏  举报