欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  互联网

荐 牛客算法周周练14题解

程序员文章站 2022-04-09 10:57:39
思维+模拟、树形DP+暴力、大数处理、字符串的子串查找比照...

B:Circle


题目描述
现在我们要把1…n这n个数字首尾连接组成一个环,使得相邻元素互质的对数尽可能多。请输出最大对数。

输入描述:
一行一个整数n(1≤ n≤ 1000)。
输出描述:
一行一个整数表示答案。

输入
4
输出
4

说明
样例的一种构造方法为1 4 3 2。

题解:输入和输出题。i 和 i+1肯定互质,1和n肯定也互质,把1到n连成一串就可以了。输入即输出QAQ

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

int main()
{
    int n;
    scanf("%d",&n);
    printf("%d\n",n);
    return 0;
}

C:Tree


题目描述
修修去年种下了一棵树,现在它已经有n个结点了。
修修非常擅长数数,他很快就数出了包含每个点的连通点集的数量。
澜澜也想知道答案,但他不会数数,于是他把问题交给了你。

输入描述:
第一行一个整数n (1≤ n ≤ 10^6),接下来n-1行每行两个整数ai,bi表示一条边 (1≤ ai,bi≤ n)。
输出描述:
输出n行,每行一个非负整数。第i行表示包含第i个点的连通点集的数量对109+7取模的结果。

示例1
输入
6
1 2
1 3
2 4
4 5
4 6
输出
12
15
7
16
9
9

题解: 如果题目只要求求出每个点的子树内联通点集数量,那很显然是 所有儿子dp值加一 的积
当时往上衍生的方案数有点难处理,我们发现显然根结点的答案就是dp值
假设我们当前处理结点x,我们已知x的父节点的答案,那么很显然为那么往上面衍生的答案数很显然为temp: ans[fa]/(dp[x]+1)
,所以ans[x]=(temp+1)*dp[x] 但是这题还有一个坑点
如果之前乘上一个dp[x]+1的时候,dp[x]+1%mod恰好为0,如今想要将其贡献消除,乘上一个逆元是做不到的 可以采用暴力消除影响

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+100;

const ll mod=1e9+7;

ll fast(ll x,ll n) {
    ll ans=1;
    for(;n;n>>=1,x=x*x%mod)
        if(n&1) ans=ans*x%mod;
    return ans;
}
ll inv(ll x) {
    return fast(x,mod-2);
}

vector<int>edge[N];
ll dp[N],ans[N],sta[N],f[N];

void dfs(int x,int fa) {
    dp[x]=1;f[x]=fa;
    for(auto &v:edge[x]) if(v!=fa) {
        dfs(v,x);
        dp[x]*=(dp[v]+1);
        dp[x]%=mod;
    }
}

void dfs2(int x,int fa) {
    if(x!=1) {
        if((dp[x]+1)%mod) {
            sta[x]=ans[fa]*inv(dp[x]+1)%mod;
            ans[x]=dp[x]*(1+sta[x])%mod;
        }
        else {
            ll temp=sta[fa]+1;
            for(auto v:edge[fa]) if(v!=x&&v!=f[fa])
                temp=temp*(dp[v]+1)%mod;
            sta[x]=temp;
            ans[x]=(temp+1)*dp[x]%mod;
        }
    }
    for(auto v:edge[x])
        if(v!=fa) dfs2(v,x);
}

int main() {
    int n;cin>>n;
    for(int i=1;i<n;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    dfs(1,0);
    ans[1]=dp[1];
    dfs2(1,0);
    for(int i=1;i<=n;i++) {
        printf("%lld\n",ans[i]);
    }
}

D:绝地求生pudg

荐
                                                        牛客算法周周练14题解
示例1
输入
1
4 6
输出
Case 1: 12

示例2
输入
2
2147483647 2147483648
10000007 531233
输出
Case 1: 4611686016279904256
Case 2: 5312333718631
荐
                                                        牛客算法周周练14题解

又是1条复杂的题目,头大QAQ

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

template<class T> inline void read(T &x) {
    x=0;
    T f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(ch<='9' && ch>='0') {
        x=x*10+(ch-'0');
        ch=getchar();
    }
    x*=f;
}

string multiple(string p,string q)
{
    string s="";
    int n,a[1000],b[1000],c[1000],la,lb,lc,temp;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    la=p.size();
    lb=q.size();
    for (int i=0; i<la; i++)   a[la-i]=p[i]-'0';
    for (int i=0; i<lb; i++)   b[lb-i]=q[i]-'0';
    lc=1;
    temp=0;
    for (int i=1; i<=la; i++) {
        temp=0;
        for (int j=1; j<=lb; j++) {
            c[i+j-1]=a[i]*b[j]+temp+c[i+j-1];
            temp=c[i+j-1]/10;
            c[i+j-1]%=10;
        }
        c[i+lb]=temp;
    }
    
    lc=la+lb;
    while(c[lc]==0 && lc>1)   lc--;
    for(int i=lc; i>=1; i--)    s+=char(c[i])+'0';
    return s;
}

ll L=110;
ll sub(ll *a,ll *b,ll La,ll Lb)
{
    if(La<Lb)    return -1;
    
    if(La==Lb) {
        for(int i=La-1; i>=0; i--) {
             if(a[i]>b[i])    break;
             else if(a[i]<b[i])   return -1;
        }
    }
    
    for(int i=0; i<La; i++) {
        a[i]-=b[i];
        if(a[i]<0)    a[i]+=10,a[i+1]--;
    }
    
    for(int i=La-1; i>=0; i--) 
        if(a[i])     return i+1;
    
    return 0;
}

string div(string n1,string n2,ll nn)
{
    string s,v;
    ll a[L],b[L],r[L];
	ll La=n1.size(),Lb=n2.size(),i,tp=La;
    fill(a,a+L,0);
    fill(b,b+L,0);
    fill(r,r+L,0);
    
    for(i=La-1; i>=0; i--)    a[La-1-i]=n1[i]-'0';
    for(i=Lb-1; i>=0; i--)    b[Lb-1-i]=n2[i]-'0';
    if(La<Lb || (La==Lb && n1<n2))    return n1;
    
    ll t=La-Lb;
    for(int i=La-1; i>=0; i--) {
         if(i>=t)    b[i]=b[i-t];
         else   b[i]=0;
    }
    
    Lb=La;
    for(int j=0; j<=t; j++) {
        ll temp;
        while((temp=sub(a,b+j,La,Lb-j))>=0) {
            La=temp;
            r[t-j]++;
        }
    }
    
    for(i=0; i<L-10; i++)    r[i+1]+=r[i]/10,r[i]%=10;
    
    while(!r[i])    i--;
    while(i>=0)    s+=r[i--]+'0';
    
    i=tp;
    while(!a[i])    i--;
    while(i>=0)    v+=a[i--]+'0';
    
    if(v.empty())    v="0";
    if(nn==1)    return s;
    if(nn==2)    return v;
    
}

int T;
string a,b;

string gcd(string x,string y) {
    string temp;
    while(y!="0") {
        temp=div(x,y,2);
        x=y;
        y=temp;
    }
    return x;
}

int main() {
    read(T);
    int pol=0;
    while(T-- ) {
        cin>>a>>b;
        string t=multiple(a,b);
        string y=gcd(a,b);
        cout<<"Case "<<++pol<<": ";
        cout<<div(t,y,1)<<endl;
    }
    return 0;
}

E:[水]悠悠碧波


题目描述
帕秋莉掌握了一种水属性魔法
这种魔法可以净化黑暗
帕秋莉发现对于一个黑暗的咒语s,可以使用这个水元素魔法净化它,净化的咒语是一个最长的字符串t,t满足以下条件:
它是s的前缀
它是s的后缀
除前缀和后缀外,它还在s中出现过至少一次
既然你都学会了,那么净化的工作就交给你了!

输入描述:
一行字符串 s ,代表黑暗咒语
输出描述:
一个字符串 t ,表示满足条件的最长净化咒语

输入
tqrwantoacthisproblembutqristooweaktodoitqr
输出
tqr

备注:
对于60%的数据,s长度≤100
对于100%的数据,s长度≤100,000
保证存在可行的净化咒语

题解:划分一下前缀、后缀和中间部分所在的区间,查找比对,if 判断就好了。

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

int main()
{
  cin>>s;
  string t;
  int n=s.size();
  for(int i=1;i<=n/3;i++)
  {
    string a=s.substr(0,i);
	string b=s.substr(i,n-2*i);
	string c=s.substr(n-i,i);
    if(a==c&&b.find(a)!=b.npos)  t=a;
  }
  cout<<t<<endl;
}

本文地址:https://blog.csdn.net/Luoxiaobaia/article/details/107328542