7

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

 3 years ago
source link: https://www.cnblogs.com/pusubazhahei/p/16123250.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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;
}

状态压缩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;
}

直接两重循环建边+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;
}

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

__EOF__


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK