补题 HNCPC2018

FGHJK

I不会斯坦纳树,E看情况补

ABCD大概率是不会补了

Fixed Point

注意到互不相同的环长最多为根号个

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int p[13][N];
int ret[300][N],id[N];
int main()
{
    int n,m,q;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        for(int i=1;i<=n;++i)p[0][i]=i;
        for(int i=1,a,b;i<=m;++i)
        {
            for(int j=1;j<=n;++j)p[i][j]=p[i-1][j];
            scanf("%d%d",&a,&b);
            reverse(p[i]+a,p[i]+b+1);
        }
        //for(int i=1;i<=n;++i)printf("%d%c",p[m][i]," \n"[i==n]);
        vector<int>vis(n+1),rs(q),ques(q);
        for(auto &v:ques)scanf("%d",&v);
        
        vector<vector<int>> Q(m);
        for(int i=0;i<q;++i)Q[ques[i]%m].push_back(i);
        
        //circ
        vector<int> circ,from(n+1),dis(n+1);
        map<int,int> hv;
        unordered_map<int,int> mp;
        int cnt=0;
        for(int i=1;i<=n;++i)
            if(!vis[i])
        {
            int L=0;
            ++cnt;
            for(int pos=i;!vis[pos];pos=p[m][pos])
                ++vis[pos],from[pos]=cnt,dis[pos]=++L;
                mp[cnt]=L;
                hv[L]=1;
                //cout<<"L"<<L<<endl;
        }
        for(auto [L,v]:hv)circ.push_back(L);
       // cout<<
       // for(auto L:circ)cout<<L<<" ";cout<<endl;
        //cout<<circ.size()<<endl;
        for(int i=0;i<circ.size();++i)id[circ[i]]=i;
        for(int i=0;i<m;++i)
            if(Q[i].size())
        {
           // cout<<"i== "<<i<<endl;
            // map<pair<int,int>,int> res;
            for(int j=1;j<=n;++j)
            {
                int u=j,v=p[i][j];
                if(from[u]!=from[v])continue;
                int L=mp[from[u]];
                int d=(dis[u]-dis[v]+L)%L;
                ret[id[L]][d]++;
                //cout<<"L=="<<L<<endl;
                //cout<<"now "<<endl;
            }
            for(auto v:Q[i])
            {
                for(auto L:circ)
                {
                    rs[v]+=ret[id[L]][(ques[v]/m)%L];
                    //cout<<v<<" "<<rs<<endl;
                }
            }
            for(int j=0;j<circ.size();++j)
            for(int k=0;k<=circ[j];++k)
            ret[j][k]=0;
        }
        for(auto v:rs)printf("%d\n",v);
    }
}

排列

注意到数据范围,考虑状压

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
ll cal(int state)
{
   return __builtin_popcount(state);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        vector<int> p(n);
        
        for(auto &v:p)scanf("%d",&v);
        sort(p.begin(),p.end());
        map<int,int> mp;
        for(int i=1,x,y;i<=m;++i)
        {scanf("%d%d",&x,&y);--x,--y;mp[x]|=1<<y;mp[y]|=1<<x;}
        vector<ll> dp(1<<n,1e18);
        dp[0]=0;
        for(int i=1;i<1<<n;++i)
        {
            int t=__builtin_popcount(i)-1;
            for(int j=0;j<n;++j)
            if(i&1<<j)
            {
                
                dp[i]=min(dp[i],dp[i^(1<<j)]+1ll*(cal(mp[j]&i)*2-cal(mp[j]))*p[t]);
            }
        }
        printf("%lld\n",dp[(1<<n)-1]);
    }
}

H千万别用树套树

注意到操作2范围很小,可以考虑暴力拆成3各部分

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct segment
{
    struct Node
    {
        int l,r,val,lz;
        int mid(){return l+r>>1;}
        bool in(int L,int R){return l>=L&&r<=R;}
        bool is_dot(){return l==r;}
    }tr[N<<2];
    void build(int u,int l,int r)
    {
        tr[u]={l,r,0,0};
        if(l==r)return;
        int mid=tr[u].mid();
        build(u<<1,l,mid);build(u<<1|1,mid+1,r);
    }
    void pushdown(int u)
    {
        if(tr[u].is_dot())return ;
        if(!tr[u].lz)return ;
        // Node &ls=tr[u<<1],&rs=tr[u<<1|1];
        tr[u<<1].val+=tr[u].lz;tr[u<<1|1].val+=tr[u].lz;
        tr[u<<1].lz+=tr[u].lz;tr[u<<1|1].lz+=tr[u].lz;
        tr[u].lz=0;
    }
    void pushup(int u)
    {
        return ;
    }
    void modify(int u,int l,int r,int x)
    {
        if(tr[u].in(l,r))
        {
            tr[u].val+=x;tr[u].lz+=x;return ;
        }
        pushdown(u);
        int mid=tr[u].mid();
        if(l<=mid)modify(u<<1,l,r,x);
        if(r>mid)modify(u<<1|1,l,r,x);
        pushup(u);
    }
    int query_dot(int u,int pos)
    {
        if(tr[u].is_dot())return tr[u].val;
        int mid=tr[u].mid();
        pushdown(u);
        if(pos<=mid)return query_dot(u<<1,pos);
        return query_dot(u<<1|1,pos);
    }
};
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        segment seg;
        seg.build(1,1,n);
        vector<int> d0(n+1),d1(n+1);
        while(q--)
        {
            int t,l,r;scanf("%d%d%d",&t,&l,&r);
            if(t==1)
            {
                seg.modify(1,l,r,1);
                if(r-l>=0)++d0[r];
                if(r-l>=1)++d1[r];
            }
            else 
            {
                int rs=seg.query_dot(1,l);
                if(r-l>0)rs-=d0[l];
                if(r-l>1)rs-=d1[l+1];
                printf("%d\n",rs);
            }
        }
    }
}

J买一送一

很一眼的傻逼题

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e5+10;
vector<int> e[N];
ll sm=0;
int a[N];
map<int,int>lst,mp;
vector<int>stk;
ll f[N];
void dfs(int u)
{
    mp[a[u]]++;
    ll back=sm;
    sm=sm-lst[a[u]]+(int)stk.size();
    f[u]=sm;

    ll t=lst[a[u]];
    lst[a[u]]=stk.size();    
    if(mp[a[u]]==1)stk.push_back(a[u]);
    for(auto v:e[u])
    {
        dfs(v);
    }
    lst[a[u]]=t;
    if(mp[a[u]]==1)stk.pop_back();
    --mp[a[u]];
    sm=back;
}
int main()
{
    int  n;
    while(scanf("%d",&n)!=EOF)
    {
        sm=0;mp.clear();lst.clear();stk.clear();
        for(int i=1;i<=n;++i)e[i].clear();
    for(int i=2,x;i<=n;++i)
    {
        scanf("%d",&x);
        e[x].push_back({i});
    }
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    dfs(1);
    for(int i=2;i<=n;++i)printf("%lld\n",f[i]);}
}

K

Use FFT

名字是FFT,一看是前缀和

#include <bits/stdc++.h>
using namespace std;
const int P=1e9+7;
using ll=long long;
void add(int &a,int b){a+=b;if(a>=P)a-=P;}
int main()
{
    int n,m,L,R;
    while(scanf("%d%d%d%d",&n,&m,&L,&R)!=EOF)
    {
        vector<int> a(n+1),b(m+1);
        for(auto &v:a)scanf("%d",&v);
        for(auto &v:b)scanf("%d",&v);
        for(int i=1;i<=m;++i)add(b[i],b[i-1]);
        int rs=0;
        for(int i=0;i<=n;++i)
        if(R-i>=0)
        add(rs,1ll*(b[min(m,R-i)]+P-((L-i-1>=0)?b[min(L-i-1,m)]:0))*a[i]%P);
        printf("%d\n",rs);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值