牛客寒假第一场题解

链接标题
A题
题意:写的很清楚
思路:找出厎为2和1的三角形然后因为里面多算了直角三角形的面积,再减去直角三角形的面积就行

#include<bits/stdc++.h>
using namespace std;
#define ll long long

inline ll read()
{
    ll num=0,w=0;
    char ch=0;
    while(!isdigit(ch))
    {
        w|=ch=='-';
        ch=getchar();
    }
    while(isdigit(ch))
    {
        num=(num<<3)+(num<<1)+(ch^48);
        ch=getchar();
    }
    return w?-num:num;
}

inline void write(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
const ll mod = 1e9+7;
struct mat
{
    ll a[15][15];
    mat()  //重载
    {
        memset(a,0,sizeof(a));
    }
};
mat mul(mat x,mat y)
{
    mat res;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
                res.a[i][j] = (res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
    return res;
}
ll qpow(int p)
{
    mat bas;//基础矩阵
    mat res;//单位矩阵
    for(int i=0; i<2; i++)
        res.a[i][i] = 1;
    bas.a[0][0] = bas.a[0][1] = bas.a[1][0] = 1;
    bas.a[1][1] = 0;
    while(p)
    {
        if(1&p)
            res = mul(res,bas);
        bas = mul(bas,bas);
        p>>=1;
    }
    return res.a[0][1];//或者res.a[1][0]
}
int main()
{
//    ll n , x ,y ,a ,b;
//    n =read();
//    x =read();y =read();a =read();b =read();
   ll n, m;
   n =read(), m = read();
   ll zhi = 0, dun =0 , deng =0 ;
   if(m<2||m<2)cout<<0 <<endl;
   else {
           zhi = 4*(n-1)%mod*(m-2)%mod+4*(m-1)*(n-2)%mod-mod-mod;
           dun +=2*(n-1)%mod*(m-2)%mod*m%mod;
           dun +=(m-1)%mod*(n-2)%mod*2*n%mod;
           deng = (m-2)%mod*(n-1)%mod*n%mod*2+(m-1)%mod*(n-2)%mod*2*m%mod;
           cout<<(deng+dun-zhi)%mod<<endl;
   }

    return 0;
}

B题
思路:概率题,两个期望和

#include <cstdio>
 #include <iostream>
 #include <algorithm>
 #include <cmath>
 #include <string>
 #include <vector>
 #include <set>
 #include <queue>
 #include <cstring>
 #include <cassert>
#define ll long long
using namespace std;
void clear(unsigned char *pta, int size )
{
    while(size>0)
    {
        *pta++ = 0;
        size --;
    }
}
int pre[100000];
int unionsearch(int root){
    int son , tmp;
    son = root;
    while(pre[root]!=root) root = pre[root];
    while(son !=root){
        tmp = pre[son];
        pre[son] = root;
        son = tmp;
    }
    return root;
}
void join(int root1 , int root2){
    int x ,y;
    x = unionsearch(root1);
    y = unionsearch(root2);
    if(x!=y){
        pre[x]=y;
    }
}
int arr[100000],brr[100000];
int main()
{
    double n , x , a ,b;
    cin >>n >>x>>a>>b;
    double sum =0 ;
    sum  = n*x/100*1.0*a+(n*(1-x/100*1.0)*b);
    printf("%.2f\n",sum) ;
}

c题(不是我负责的领域TAT)
d题
思路:???不会有人不会把

#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;cin >>n;
    vector<int> v;
    for(int i=0;i<n-1;i++){
        int k1 ;cin>>k1;
        v.push_back(k1);
        }
    sort(v.begin(),v.end());
    int num =1;int f=0 ;
    for(int i=0;i<n-1;i++){
        if(v[i]!=num){
            cout<<num;
            f =1 ;
            break;
        }num++;
    }
    if(!f)cout<<n;cout<<endl;
}

E题
思路:看着像数论,其实是暴力哒,根据题意模拟就行

#include<bits/stdc++.h>
#define ll long long

using namespace std;

inline ll read()
{
    ll num=0,w=0;
    char ch=0;
    while(!isdigit(ch))
    {
        w|=ch=='-';
        ch=getchar();
    }
    while(isdigit(ch))
    {
        num=(num<<3)+(num<<1)+(ch^48);
        ch=getchar();
    }
    return w?-num:num;
}

inline void write(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}

ll ***(ll n){ 
    ll num = 2;
    ll  x=sqrt(n);
    for(ll i=2;i<=x;i++){
        if(n%i==0){
            if(i!=x || n/i!=i){ 
                   num+=2;
            }
            else num++;
        }
    }
    return num;
}

int main()
{
    ll n ;
   n =read();
    ll sum =0;
    n = ***(n);
    while(n != 2)
    {
        n = ***(n);
        sum ++;
    }
    cout << sum+1 << endl;
    return 0;
}


F题(赛后补的)
思路:有两种,官方的是并查集,另一种是深搜,dfs的没了解,就学了一下并查集的做法,并查集的做法就是:
1.先判断出黑点的两种存在方式①在路的尽头②路的里面包含
2.通过两种存在方式考虑做法,第一种很简单,直接累加就行第二种比较麻烦,因为他是在路的里面所以需要画个图感受一下在这个黑点的两边的白点是可以通过相乘的数量就是该白点包含这个黑点的路径数量(后面的需要和这个容斥一下)
3.关于第二个里面两边的白点是可以通过相乘的数量具体操作使用并查集来存储在同一边的白点数量

#include <vector>
#include<stdio.h>
#include<string.h>
#include <cstring>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <set>
#include<cstring>
#include<queue>
#include<assert.h>
#define ll long long
#define MODD 1000000007
#define  pii  pair<int,int>
#include<stdio.h>
#include<string.h>
//#define  ll long long
using namespace std;
const ll maxn = 1e7;
ll fa[maxn];
ll t[maxn ], knm[maxn]={0};

int find(int x ){
    if(fa[x]==x)return x ;
    return find(fa[x]);
}
void un(int x , int y){
    int aa = find(x);
    int bb = find(y);
    if(aa!=bb){
        if(knm[aa]>knm[bb]){
            knm[aa] +=knm[bb]+1;
        fa[bb] = fa[aa];
        }
            else {
        knm[bb] +=knm[aa]+1;
        fa[aa] = fa[bb];
    }

    }


}

ll black(vector<int > tmp) {
    ll len = tmp.size();
    ll sum =0 ;
    if(len ==0 )return 0;
    for(int i=0;i<len;i++){
        sum +=tmp[i];
    }
    ll num[len]; ll s=tmp[0] ;
    ll dp[len]={0};num[0] =s ;
    for(int i=1;i<len;i++){
        num[i] = s+= tmp[i];
    }
    for(int i=1;i<len;i++){
        dp[i] = dp[i-1] + num[i-1]*tmp[i];
    }
    return dp[len-1]+sum ;
}
vector<int >g[111111];
int main(){
    int n;cin >>n;
    for(int i=1;i<=n;i++){
        fa[i] = i;
        //knm[i] =1 ;
    }
    string s ;cin >>s;
    for(int i=0;i<n-1;i++){
        int l , r;
        cin >>l>>r;
        g[l].push_back(r);
        g[r].push_back(l);
        if(s[l-1]==s[r-1]&&s[l-1]=='W'){
            un(r,l);
        }
    }ll sum =0 ;
    for(int i=1;i<=n;i++)t[i] = knm[find(i)]+1;
    for(int i=1 ;i<=n;i++){
        if(s[i-1]=='W')continue ;
        else {
            vector<int > tmp ;
            for(int j =0 ;j<g[i].size();j++){
                if(s[g[i][j]-1]=='W')tmp.push_back(t[g[i][j]]);
            }
            sum +=black(tmp);
//            cout<<sum<<endl;
        }
    }
    cout<<sum<<endl;
}

G 题
思路:就是保存相同字符的位置,然后去判断最小的数量即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long

inline ll read()
{
    ll num=0,w=0;
    char ch=0;
    while(!isdigit(ch))
    {
        w|=ch=='-';
        ch=getchar();
    }
    while(isdigit(ch))
    {
        num=(num<<3)+(num<<1)+(ch^48);
        ch=getchar();
    }
    return w?-num:num;
}

inline void write(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
const int mod = 1e9+7;
struct mat
{
    ll a[15][15];
    mat(){ //重载
        memset(a,0,sizeof(a));
    }
};
mat mul(mat x,mat y)
{
    mat res;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                res.a[i][j] = (res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
    return res;
}
ll qpow(int p)
{
    mat bas;//基础矩阵
    mat res;//单位矩阵
    for(int i=0;i<2;i++)
        res.a[i][i] = 1;
    bas.a[0][0] = bas.a[0][1] = bas.a[1][0] = 1;
    bas.a[1][1] = 0;
    while(p)
    {
        if(1&p) res = mul(res,bas);
        bas = mul(bas,bas);
        p>>=1;
    }
    return res.a[0][1];//或者res.a[1][0]
}
int main(){
//    ll n , x ,y ,a ,b;
//    n =read();
//    x =read();y =read();a =read();b =read();
    int n , k;cin >>n>>k;
    string s; 
    cin >>s;
    vector <int > v[30];
    int arr[5000]={0};int ma =-1 ;int pos[5000] = {0};int cnt =0 ;
    for(int i=0;i<n;i++){

            arr[s[i]-'a'+1]++ ;
            if(k<=arr[s[i]-'a'+1]&&!pos[ s[i]-'a'+1]){
                pos[ s[i]-'a'+1] = 1 ;
            }
            //cout<< arr[s[i]-'a'+1]<<endl;
            ma = max(ma , arr[s[i]-'a'+1]);

            v[s[i]-'a'+1 ].push_back(i+1 );

    }
    //cout<<ma<<endl;
    int l =0 ,r  =0 ;int len =0x7f7f7f;
    if(ma <k)cout<<-1<<endl;
    else {
        for(int i=1;i<=26;i++){
        //    cout<<"/"<<endl;
            if(pos[i]){
                for(int j = 0;j<v[i].size()-k+1;j++){
                    len = min(len, v[i][j+k-1]-v[i][j]+1);
                }

            }
        }
        cout<<len ;
        cout<<endl;
    }
    return 0;
}

H题
思路:把零换成1存一下位置,把一换成0存一下位置,然后用上面相似的思路解决就行

#include<bits/stdc++.h>
using namespace std;
string s;
vector<int>v0,v1;       //v0存字符'0'的坐标位置,v1存字符'1'的坐标位置
int main(){

    int n,k,i,j;
    cin>>n>>k;
    cin>>s;
    v0.push_back(-1);
    v1.push_back(-1);
    for(i=0;i<n;i++){
        if(s[i]=='0')v0.push_back(i);
        else v1.push_back(i);
    }
    v0.push_back(n);
    v1.push_back(n);
    int ma=0;
    if(v0.size()-2<=k)ma=n;
    else{
        for(i=1,j=k;j<v0.size()-1;i++,j++){
            ma=max(ma,v0[j+1]-v0[i-1]-1);
        }
    }
    if(v1.size()-2<=k)ma=n;
    else{
        for(i=1,j=k;j<v1.size()-1;i++,j++){
            ma=max(ma,v1[j+1]-v1[i-1]-1);
        }
    }
    cout<<ma;
}

I题(赛后补题)
思路:DP,一开始想到要比较三次(但是对DP 没什么感觉),直接比较三次a,b,c 找出最大的就行

// I want to AC


#include <vector>
#include<stdio.h>
#include<string.h>
#include <cstring>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <set>
#include<cstring>
#include<queue>
#include<assert.h>
#define ll long long
#define MODD 1000000007
#define  pii  pair<int,int>
#include<stdio.h>
#include<string.h>
#include<bits/stdc++.h>
//#define  ll long long
using namespace std;
const int maxn = 1e6+7;
#define FOR(i, x, y) for (ll i = (x), _##i = (y); i < _##i; ++i)


int n; ll a,b,c ;
ll dp[maxn];
int main() {
    ios::sync_with_stdio(false);
    cin >>n;
    cin >>a>>b>>c;
    string s; cin >>s;
    for(int i=0;i<n;i++){
        if(i>0) dp[i]             =dp[i-1];
        if(i>=3&&s[i-3]=='n'&&s[i-2]=='i'&&s[i-1]=='c'&&s[i]=='o')
            dp[i] = max(dp[i],dp[i-3]+a);
         if(s[i-5]=='n'&&s[i-4]=='i'&&s[i-3]=='c'&&s[i-2]=='o'&&s[i-1]=='n'&&s[i]=='i'&&i>=5)
            dp[i] = max(dp[i],dp[i-5]+b);
         if(s[i-9]=='n'&&s[i-8]=='i'&&s[i-7]=='c'&&s[i-6]=='o'&&s[i-5]=='n'&&s[i-4]=='i'&&s[i-3]=='c'&&s[i-2]=='o'&&s[i-1]=='n'&&s[i]=='i' &&i-9>=0)
            dp[i] = max(dp[i],dp[i-9]+c);

    }
    cout<<dp[n-1]<<endl;
    return 0;



}

J题(不会)

全部评论

相关推荐

点赞 评论 收藏
分享
有趣的牛油果开挂了:最近这个阶段收到些杂七杂八的短信是真的烦
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务