coderforces #678 div2

A
在这里插入图片描述

using namespace std;
#include <bits/stdc++.h>
#define int long long
 
void solve()
{
    int n,m;
    cin>>n>>m;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        int xx;
        cin>>xx;
        sum+=xx;
    }
    if(sum==m)
        cout<<"YES"<<"\n";
    else
        cout<<"NO"<<"\n";
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
    cin >> _;
    while (_--)
        solve();
    return 0;
}

B
在这里插入图片描述

using namespace std;
#include <bits/stdc++.h>
#define int long long
const int N=1e5+5;
int flag[N],prime[N],pnum;
void CreatePrime()
{
    pnum=0;
    for(int i=0;i<N;i++)
    {
        flag[i]=1;
    }
    for(int i=2;i<=N;i++)
    {
        if(flag[i]==1)
            prime[pnum++]=i;
        for(int j=0;j<pnum&&prime[j]*i<=N;j++)
        {
            flag[prime[j]*i]=0;
            if(i%prime[j]==0)
                break;
        }
    }
}
void solve()
{
    int n;
    cin>>n;
    int xx=(n-1)*4;
    int yy=0;
    while(flag[xx]==0||flag[yy])
    {
        xx++;
        yy++;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)
                cout<<yy<<" ";
            else
                cout<<4<<" ";
        }
        cout<<endl;
    }
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    CreatePrime();
    int _ = 1;
    cin >> _;
    while (_--)
        solve();
    return 0;
}

C
在这里插入图片描述

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
vector<int>uu,vv;
const int kk=1e3+5;
int inv[kk];
void getInv()
{
    inv[1]=1;
    for(int i=2;i<kk;i++)
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
int fact[kk];
int invfact[kk];
void init()
{
    fact[0]=1;
    invfact[0]=1;
    for(int i=1;i<kk;i++)
    {
        fact[i]=fact[i-1]*i%mod;
        invfact[i]=invfact[i-1]*inv[i]%mod;
    }
}
int getC(int m,int n)
{
    if(m<0||m>n)
        return 0;
    return fact[n]*invfact[m]%mod*invfact[n-m]%mod;
}
void solve()
{
    uu.clear();
    vv.clear();
    int n,x,pos;
    cin>>n>>x>>pos;
    int l=0,r=n;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(mid<=pos)
        {
            l=mid+1;
            if(mid!=pos)
                uu.push_back(mid);
        }
        else
        {
            r=mid;
            vv.push_back(mid);
        }
    }
    int a=uu.size();
    int b=vv.size();
    int res=getC(a,x-1)*getC(b,n-x)%mod;
    int ans=fact[a]*fact[b]%mod*fact[n-a-b-1]%mod;
    res=res*ans%mod;
    cout<<res;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    getInv();
    init();
    int _ = 1;
    //cin >> _;
    while (_--)
        solve();
    return 0;
}

D
题意: 有一颗有根树,根为1,每个节点上面都有一个权值,这些权值都会不断向下面的分支移动,问使得每个叶节点上权值最大的值最小是多少。

题解: 可以统计每个子树的权值和是多少,那么每个叶节点最后的权值就是总的权值和/叶节点数目。这个结论一开始就是这么猜的,然后一直觉得证明不了,感觉无法让左边分支的节点走到右边分支,但是当这种情况出现时,答案会在下面的子树取得。证明不了,就口胡数学归纳法过了吧。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+5;
struct node
{
    int v,next;
};
node no[maxn*10];
int head[maxn];
int cnt=1;
int a[maxn];
int b[maxn];
void init()
{
    memset(head,0,sizeof(head));
}
void add(int x,int y)
{
    no[cnt].v=y;
    no[cnt].next=head[x];
    head[x]=cnt;
    cnt++;
}
int ans=0;
void dfs(int u)
{
    if(head[u]==0)
        b[u]=1;
    else
        b[u]=0;
    for(int i=head[u];i;i=no[i].next)
    {
        int v=no[i].v;
        dfs(v);
        b[u]+=b[v];
        a[u]+=a[v];
    }
    ans=max(ans,(a[u]+b[u]-1)/b[u]);
}
void solve()
{
    int n;
    cin>>n;
    for(int i=2;i<=n;i++)
    {
        int x;
        cin>>x;
        add(x,i);
    }
    for(int i=1;i<=n;i++)
        cin>>a[i];
    dfs(1);
    cout<<ans;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--)
        solve();
    return 0;
}

E
题意:给你一个数组,求子数组mex 的集合S ,求mex(S);
思路:求子数组会不会出现 mex=x的情况 ,有的话肯定在相邻的两个x之间及现在和last 之间,并且1-x-1的出现的last最小值肯定比last[x]大,才是,然后直接维护更新last, 维护last 的时候记得最后一段。
很显然找一段的最小值线段树维护,单点更新。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e9+5;
const int maxn=1e5+5;
int a[maxn];
int last[maxn];
set<int>se;
int tree[maxn*4];
void build(int l,int r,int t)
{
    if(l==r)
        tree[t]=last[l];
    else
    {
        int mid=(l+r)>>1;
        build(l,mid,t<<1);
        build(mid+1,r,t<<1|1);
        tree[t]=min(tree[t<<1],tree[t<<1|1]);
    }
}
void update(int l,int r,int t,int x,int y)
{
    if(l==r)
    {
        tree[t]=y;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        update(l,mid,t<<1,x,y);
    else
        update(mid+1,r,t<<1|1,x,y);
    tree[t]=min(tree[t<<1],tree[t<<1|1]);
}
int query(int l,int r,int t,int L,int R)
{
    if(l>=L&&r<=R)
        return tree[t];
    if(l>R||r<L)
        return inf;
    int mid=(l+r)>>1;
    int ans=inf;
    if(mid>=L)
        ans=min(ans,query(l,mid,t<<1,L,R));
    if(mid<R)
        ans=min(ans,query(mid+1,r,t<<1|1,L,R));
    return ans;
}
void solve()
{
    se.clear();
    memset(last,0,sizeof(last));
    int n;
    cin>>n;
    build(1,n,1);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        int xx=a[i];
        if(xx==1)
            se.insert(2);
        else
        {
            se.insert(1);
            if(query(1,n,1,1,xx-1)>last[xx])
                se.insert(xx);
        }
        last[xx]=i;
        update(1,n,1,xx,i);
    }
    for(int i=2;i<=n+1;i++)
    {
        if(query(1,n,1,1,i-1)>last[i])
            se.insert(i);
    }
    int now=1;
    for(auto s:se)
    {
        if(s!=now)
        {
            cout<<now;
            return;
        }
        now++;
    }
    cout<<now;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--)
        solve();
    return 0;
}

F
在这里插入图片描述

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
const int mod=998244353;
int num[maxn];
int dp[maxn];
int fastpow(int a,int n)
{
    if(n<0)
        return 0;
    int res=1;
    int temp=a;
    while(n)
    {
        if(n&1)
            res=res*temp%mod;
        temp=temp*temp%mod;
        n>>=1;
    }
    return res%mod;
}
void solve()
{
    int N=1e5;
    memset(dp,0,sizeof(dp));
    memset(num,0,sizeof(num));
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        num[x]+=y;
    }
    int c,sm,sm2,w;
    for(int i=N;i;i--)
    {
        c=sm=sm2=w=0;
        for(int j=i;j<=N;j+=i)
        {
            c=c+num[j];
            sm=(sm+j*j%mod*num[j]%mod)%mod;
            sm2=(sm2+w*2%mod*j%mod*num[j]%mod+j*j%mod*num[j]%mod*(num[j]-1)%mod)%mod;
            w=(w+num[j]*j%mod)%mod;
            dp[i]=(dp[i]-dp[j]+mod)%mod;
        }
        dp[i]=(dp[i]+(c-1)%mod*sm%mod*fastpow(2,c-2)%mod+sm2*((c-2)%mod*fastpow(2,c-3)%mod+fastpow(2,c-2))%mod)%mod;
    }
    cout<<dp[1];
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--)
        solve();
    return 0;
}

反演
一个函数 f(n)=g(i)的和 i是n的因子或者倍数,g[n]=f[i]*mu[n/i 或者 i/n]的和叫莫比乌斯反演

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
const int mod=998244353;
int num[maxn];
int dp[maxn];
int mu[maxn];
bool isnp[maxn];
vector<int>primes;
void init(int n)
{
    memset(isnp,false,sizeof(isnp));
    primes.clear();
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!isnp[i])
            primes.push_back(i),mu[i]=-1;
        for(int p:primes)
        {
            if(p*i>n)
                break;
            isnp[p*i]=i;
            if(i%p==0)
            {
                mu[p*i]=0;
                break;
            }
            else
                mu[p*i]=mu[p]*mu[i];
        }
    }
}
int fastpow(int a,int n)
{
    if(n<0)
        return 0;
    int res=1;
    int temp=a;
    while(n)
    {
        if(n&1)
            res=res*temp%mod;
        temp=temp*temp%mod;
        n>>=1;
    }
    return res%mod;
}
void solve()
{
    int N=1e5;
    memset(dp,0,sizeof(dp));
    memset(num,0,sizeof(num));
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        num[x]+=y;
    }
    int c,sm,sm2,w;
    for(int i=N;i;i--)
    {
        c=sm=sm2=w=0;
        for(int j=i;j<=N;j+=i)
        {
            c=c+num[j];
            sm=(sm+j*j%mod*num[j]%mod)%mod;
            sm2=(sm2+w*2%mod*j%mod*num[j]%mod+j*j%mod*num[j]%mod*(num[j]-1)%mod)%mod;
            w=(w+num[j]*j%mod)%mod;
        }
        dp[i]=(dp[i]+(c-1)%mod*sm%mod*fastpow(2,c-2)%mod+sm2%mod*((c-2)%mod*fastpow(2,c-3)%mod+fastpow(2,c-2))%mod)%mod;
    }
    int ans=0;
    for(int i=1;i<=N;i++)
    {
        if(dp[i]==0)
            continue;
        ans=(ans+mod+mu[i]*dp[i])%mod;
    }
    cout<<ans;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
    int n=1e5;
    init(n);
    //cin >> _;
    while (_--)
        solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值