牛客周赛 Round 7【题解完成】

86 阅读3分钟
题目难度知识点
A 游游的you矩阵签到/暴力枚举
B 游游的01串操作枚举/DP
C 游游的正整数★★二分
D 游游的选数乘积★★状态计数DP

image.png 打的是一坨,不过确实不太会C和D。确实之前没搞过类似的题目。本套题C是二分应该是可以做出来的但是没做出来,主要没发现那个性质。唉还是太菜了。

游游的you矩阵

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
string s[N];
int n,m,ans;
void solve(int x,int y)
{
    map<char,int>mp;
    mp[s[x][y]]=1,mp[s[x][y+1]]=1,mp[s[x+1][y]]=1,mp[s[x+1][y+1]]=1;
    if(mp['y']&&mp['o']&&mp['u']) ans++;
}
int main(void)
{
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>s[i];
    for(int i=0;i<n-1;i++) 
        for(int j=0;j<m-1;j++) solve(i,j);
    cout<<ans;
    return 0;
}

游游的01串操作

最终状态就两种,枚举求一个min即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
string s,temp1,temp2;
LL ans1,ans2;
int main(void)
{
    cin>>s;
    while(temp1.size()<s.size()) temp1+="01";
    while(temp2.size()<s.size()) temp2+="10";
    for(int i=0;i<s.size();i++)
    {
        if(s[i]!=temp1[i]) ans1+=i+1;
        if(s[i]!=temp2[i]) ans2+=i+1;
    }
    cout<<min(ans1,ans2);
    return 0;
}

状态机DP搞

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
string s,temp1,temp2;
LL f[N][2];//f[i]前i个字符且最后是[j]的最小花费
int main(void)
{
    cin>>s;
    if(s[0]=='0')  f[0][0]=0,f[0][1]=1;
    else f[0][0]=1,f[0][1]=0;
    for(int i=1;i<s.size();i++)
    {
        if(s[i]=='1')
        {
            f[i][1]=f[i-1][0];
            f[i][0]=f[i-1][1]+i+1;
        }else{
            f[i][0]=f[i-1][1];
            f[i][1]=f[i-1][0]+i+1;
        }
    }
    cout<<min(f[s.size()-1][0],f[s.size()-1][1]);
    return 0;
}

游游的正整数

image.png 令 s = b-a; 题意是若s能落在[0,0][1* l,1* r],[2* l,2* r],[3* l,3* r],.....,[k*l,k *r] (k是非负整数)的某个区间中,就有解,否则无解,只需要两次二分枚举k,一次枚举最大k,一次枚举最小k。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
LL t,a,b,l,r;
int main(void)
{
    cin>>t;
    while(t--)
    {
        cin>>a>>b>>l>>r;
        LL temp=b-a;
        LL l1=0,r1=1e9;
        while(l1<r1)
        {
            LL mid=(l1+r1)/2;
            if(r*mid>=temp) r1=mid;
            else l1=mid+1;
        }
        if(l1*l<=temp&&temp<=l1*r)
        {
            LL l2=0,r2=1e9;
            while(l2<r2)
            {
                LL mid=(l2+r2+1)/2;
                if(l*mid<=temp) l2=mid;
                else r2=mid-1;
            }
            cout<<l1<<" "<<l2<<endl;
        }else cout<<-1<<endl;
    }
    return 0;
}

游游的选数乘积

image.png

image.png

image.png

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=100;
typedef long long int LL;
LL cnt[N][N],n,k;
int main(void)
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
    {
        int x; cin>>x;
        int cnt2=0,cnt5=0;
        while(x%2==0) x/=2,cnt2++;
        while(x%5==0) x/=5,cnt5++;
        cnt[cnt2][cnt5]++;
    }
    LL ans1=0,ans2=0;
    for(int i=0;i<32;i++)//枚举第一种状态
            for(int j=0;j<15;j++)
                for(int ii=0;ii<32;ii++)//枚举第二种状态
                        for(int jj=0;jj<15;jj++)
                        {
                            if(i+ii<k || j+jj<k) continue;
                            if(i==ii&&j==jj)//
                            {
                                ans1+=cnt[i][j]*(cnt[i][j]-1)/2;
                            }else
                            {
                                ans2+=cnt[i][j]*cnt[ii][jj];
                            }
                        }
    cout<<ans1+ans2/2;
    return 0;
}