Wannafly挑战赛16

https://www.nowcoder.com/acm/contest/113#question

a题

等价于规定4种石子相同种类的绝对顺序,然后石子种类不同间随便你排

因为最后总要排成sum 个 我们 从sum个中去a个按顺序放a就行了 所以答案是c(a,sum)c(b,sum-a)c(c,sum-a-b); 暴力算一算

#include <stdio.h>
using namespace std;
const int maxn = 1e5+9;
const int mod = 1e9+7;
typedef long long int  ll;
ll quick(ll a,ll b){
    ll ret = 1;
    while (b) {
        if(b&1){
            ret*=a;
            ret%=mod;
        }
        a*=a;
        a%=mod;
        b>>=1;
    }
    return ret;
}
int main(){
    int a,b,c,d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    int sum = a+b+c+d;
    ll ans = 1;
    for(int i=0;i<a;i++){
        ll now = sum-i;
        ans*=now;
        ans%=mod;
    }
    for(int i=1;i<=a;i++){
        ans*=quick(i,mod-2);
        ans%=mod;
    }
    sum-=a;
     
    for(int i=0;i<b;i++){
        ll now = sum-i;
        ans*=now;
        ans%=mod;
    }
    for(int i=1;i<=b;i++){
        ans*=quick(i,mod-2);
        ans%=mod;
    }
    sum-=b;
    for(int i=0;i<c;i++){
        ll now = sum-i;
        ans*=now;
        ans%=mod;
    }
    for(int i=1;i<=c;i++){
        ans*=quick(i,mod-2);
        ans%=mod;
    }
    printf("%lld\n",ans);
    return 0;
}

 

b题

结论就是减去中位数,注意偶数个数的时候的情况,证明参考 糖果传递

#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 2e5+9;
const int mod = 1e9+7;
typedef long long int  ll;
int a[maxn];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=n;i<m+n;i++){
        int ttt;
        scanf("%d",&ttt);
        a[i] = -ttt;
    }
    sort(a,a+m+n);
    if((m+n)&1){
        int bb = a[(m+n)/2];
        ll ans = 0;
        for(int i=0;i<n+m;i++){
            ans+=abs(a[i]-bb);
        }
        ans+=abs(bb);
        printf("%lld\n",ans);
    }else{
        int bb = a[(m+n)/2];
        ll ans1 = 0;
        for(int i=0;i<n+m;i++){
            ans1+=abs(a[i]-bb);
        }
        ans1+=abs(bb);
        bb = a[(m+n)/2-1];
        ll ans2 = 0;
        for(int i=0;i<n+m;i++){
            ans2+=abs(a[i]-bb);
        }
        ans2+=abs(bb);
        printf("%lld\n",min(ans1,ans2));
        
    }
    return 0;
}

c题

l,r会有1的贡献

(l,r/3)会有1的贡献

(l,r/5) 会有1的贡献 所以把这些区间求和处以区间长度就是答案,具体就是预处理奇数项调和级数的前缀和搞搞

#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 5e6+9;
const int mod = 998244353;
typedef long long int  ll;
ll kk[maxn];
ll quick(ll a,ll b){
    ll ret = 1;
    while (b) {
        if(b&1){
            ret*=a;
            ret%=mod;
        }
        a*=a;
        a%=mod;
        b>>=1;
    }
    return ret;
}

int main(){
    for(int i=1;i<maxn;i++){
        kk[i] = quick(2*i-1,mod-2);
        kk[i]+=kk[i-1];
        kk[i]%=mod;
    }
    int T;
    scanf("%d",&T);
    while (T--) {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        ll ii = (r+l)/2/l;
        ll ans = (((kk[ii]*r)%mod-l*ii)%mod+mod)%mod;
        ans*=quick(r-l,mod-2);
        ans%=mod;
        printf("%lld\n",ans);
        
    }
    return 0;
}

d题

基本思路就是把时间转成距离 做最段路

就是有n层  每层a*b个点 每层里每个点之间转移有距离 层与层之间对应点转移有距离

然后我们发现最优解可以一层一层推 然后二维点可以转成一维的转移,因为每行从i列到j列的转移代价一样

这样就成了个dp

我还特傻搞了dij堆优化和spfa明显状态爆炸....还是太菜了

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 109;
    int a,b,c,n;
int xx[maxn];
int yy[maxn];
int ff[maxn][maxn];
int gg[maxn][maxn];
int hh[22][maxn][maxn];
ll dis[maxn][maxn];
int ww[maxn];
int tt[maxn];
void go(int nowceng){
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            for(int k = 1;k<=a;k++){
                dis[k][j] = min(dis[k][j],dis[i][j]+ff[i][k]);
            }
        }
    }
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            for(int k = 1;k<=b;k++){
                dis[i][k] = min(dis[i][k],dis[i][j]+gg[j][k]);
            }
        }
    }
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            dis[i][j]+=ww[nowceng+1]/hh[tt[nowceng+1]][i][j];
            if(ww[nowceng+1]%hh[tt[nowceng+1]][i][j]!=0) dis[i][j]++;
        }
    }
}
int main()
{
 
    scanf("%d%d%d%d",&a,&b,&c,&n);
    /*
    pp.push(node{10,1,1,1});
    pp.push(node{12,1,1,1});
    node tmp = pp.top();
    cout<<tmp.val<<endl;
    */
    for(int i=1;i<=a;i++){
        scanf("%d",&xx[i]);
    }
    for(int i=1;i<=b;i++){
        scanf("%d",&yy[i]);
    }
    for(int i=1;i<=a;i++){
        for(int j=1;j<=a;j++){
            scanf("%d",&ff[i][j]);
        }
    }
    for(int i=1;i<=b;i++){
        for(int j=1;j<=b;j++){
            scanf("%d",&gg[i][j]);
        }
    }
    for(int k=1;k<=a;k++){
        for(int i=1;i<=a;i++){
            for(int j=1;j<=a;j++){
                ff[i][j] = min(ff[i][j],ff[i][k]+ff[k][j]);
            }
        }
    }
    for(int k=1;k<=b;k++){
        for(int i=1;i<=b;i++){
            for(int j=1;j<=b;j++){
                gg[i][j] = min(gg[i][j],gg[i][k]+gg[k][j]);
            }
        }
    }
    for(int i=1;i<=c;i++){
        for(int j=1;j<=a;j++){
            for(int k = 1;k<=b;k++){
                scanf("%d",&hh[i][j][k]);
            }
        }
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&ww[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&tt[i]);
    }
    memset(dis,0x3f,sizeof(dis));
 
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            dis[i][j] = xx[i]+yy[j];
        }
    }
    for(int i=0;i<n;i++){
        go(i);
    }
    ll ans= 0x3f3f3f3f3f3f3f3f;
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            ans = min(ans,dis[i][j]);
        }
    }
    printf("%lld\n",ans);
    return 0;
}
/*
2 2 1 1
1 100
1 100
0 10
5 0
0 7
6 0
2 3
4 5
1001
1
*/

e题

核心是距离和时间的等价转换

首先这个图是环套数,先把环处理出来,树处理出来

对换上的点插入只要找到一个基准点转化就行了

然后是对树上的点的操作,我们都需要转化为树根的状态,可是这样会有混淆,不是一个子树的会混在一起,所以我们需要区分,考虑数据结构,用dfs序维护需要查询的子树,所以用一颗可持久化线段树维护,距离加时间作为根的入口,然后维护dfs序,这样查询就是从时间加根入口查询一段区间(子树)的和,插入就是在对应的距离加时间查在dfs序上,注意树上的点总会到环上,要维护一下啥时候会到环上

一开始想的是外面是dfs序,里面是距离加时间,然后发现这样根本不能查询一段dfs序,是不对的

#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 5e5+9;
int a[maxn];
int in[maxn];
int type[maxn];
int deep[maxn],ldfs[maxn],rdfs[maxn];
int bl[maxn];
int ndfs=0;
int cirt[maxn];
vector<int> circonv[maxn];
int fcirt[maxn];
int getpos(int now,int val,int tt){
   return circonv[ cirt[now] ]
   [((int)(circonv[ cirt[now] ].size())-fcirt[now]+tt)%(int)(circonv[ cirt[now] ].size())]+=val;
}
vector<int> todolist[maxn*2];
queue<int> qq;
struct EDGE{
    int v,nex;
}e[maxn];
int tot =0;
 
int head[maxn];
void addedge(int u,int v){
    e[tot] = (EDGE){v,head[u]};
    head[u] = tot++;
}
struct Node{
    int lson,rson,sum;
}node[60*maxn];
int rt[maxn*2];
int nodecnt = 0;
int build(int l,int r){
    int now = nodecnt++;
    node[now] = (Node){-1,-1,0};
    if(l==r){
        return now;
    }
    int mid = (l+r)>>1;
    node[now].lson = build(l,mid);
    node[now].rson = build(mid+1,r);
    return now;
}
void dfs(int now,int dep,int belo){
    bl[now] = belo;
    ldfs[now] = ++ndfs;
    deep[now] = dep;
    for(int i=head[now];i!=-1;i=e[i].nex){
        int v = e[i].v;
        dfs(v,dep+1,belo);
    }
    rdfs[now] = ndfs;
}
int insert(int root,int l,int r,int pos){
    int now = nodecnt++;
    node[now] = node[root];
    node[now].sum++;
    if(l==r) return now;
    int mid = (l+r)>>1;
    if(pos<=mid) node[now].lson = insert(node[now].lson,l,mid,pos);
    else node[now].rson = insert(node[now].rson,mid+1,r,pos);
    return now;
}
int query(int root,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr){
        return node[root].sum;
    }
    int mid=(l+r)>>1;
    if(qr<=mid) return query(node[root].lson,l,mid,ql,qr);
    if(ql>mid) return query(node[root].rson,mid+1,r,ql,qr);
    return query(node[root].lson,l,mid,ql,qr)+query(node[root].rson,mid+1,r,ql,qr);
}
int main(){
 
    memset(head,-1,sizeof(head));
    int n;
    scanf("%d",&n);
    int last = 0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        in[a[i]]++;
        addedge(a[i],i);
    }
    for(int i=1;i<=n;i++){
        if(in[i]==0) {
            qq.push(i);
            type[i] = 1;
             
        }
    }
    while(!qq.empty()){
        int tmp = qq.front();
        qq.pop();
        in[a[tmp]]--;
        if(in[a[tmp]]==0) {
            qq.push(a[tmp]);
            type[a[tmp]] = 1; 
        }
    }
    for(int i=1;i<=n;i++){
        if(type[i]==0){
            int nex = i;
            int cntt = 0;
            while(type[nex]==0){
                type[nex] = 2;
                cirt[nex] = i;
                fcirt[nex] = cntt++;
                nex = a[nex];
            }
            circonv[i].resize(cntt);
        }
    }
     
    for(int i=1;i<=n;i++){
        if(type[i]==1 &&type[a[i]]==2){
            dfs(i,0,a[i]);
        }
    }
    build(1,ndfs);
    int m;
    scanf("%d",&m);
    for(int tt=0;tt<m;tt++){
        int now;
        scanf("%d",&now);
        now^=last;
        for(int i=0;i<todolist[tt].size();i++){
            int todo = todolist[tt][i];
            getpos(todo,1,tt);
        }
        if(type[now] == 1){
            rt[deep[now] + tt]=insert(rt[deep[now] + tt],1,ndfs,ldfs[now]);
            last = query(rt[deep[now]+tt],1,ndfs,ldfs[now],rdfs[now]);
            todolist[deep[now]+tt+1].push_back(bl[now]);
        }else{
            last = getpos(now,1,tt);
        }
        printf("%d\n",last);
    }
    return 0;
}

 f留坑

 

 
 
posted @ 2018-06-03 00:33  tjucxz  阅读(112)  评论(0编辑  收藏  举报