第十三屆藍橋杯省賽C/C++ B組

巴扎嘿~發表於2022-04-09

@

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=1e4+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砍竹子

這個沒時間寫了,隨便寫的

相關文章