2019牛客国庆集训派对day4

比赛链接
https://ac.nowcoder.com/acm/contest/1109?&headNav=www#question
B
设d[x]表示x到其最小生成树上父节点的距离。
则对于非树边x-y,如果d[y]=w(x,y),就意味着从x到y也可以作为最小生成树的一部分。(这个判断可以用类似dijstra的方法实现)
考虑贪心构造答案,只要让一个点周围所有可能进入最小生成树的边都割断即可。
因此对于每个点,计算和它相连的可能进入最小生成树的边的个数,然后取一次最小值即可。
代码如下

/*
设d[x]表示x到其最小生成树上父节点的距离。
则对于非树边x-y,如果d[y]=w(x,y),就意味着从x到y也可以作为最小生成树的一部分。(这个判断可以用类似dijstra的方法实现) 
考虑贪心构造答案,只要让一个点周围所有可能进入最小生成树的边都割断即可。 
因此对于每个点,计算和它相连的可能进入最小生成树的边的个数,然后取一次最小值即可。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=50+5;
const int maxm=maxn*maxn;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,m;
struct node{
    int from,to;
    ll w;
    bool operator<(const node& h)const{return wq;
int deg[maxn],vis[maxn];
ll d[maxn];
void init(){
    memset(head,0,sizeof(head));
    tot=1; 
    memset(d,INF,sizeof(d));
    memset(deg,0,sizeof(deg));
    memset(vis,0,sizeof(vis));
    while(q.size()) q.pop();
}
void dj(){
    q.push(make_pair(0,1));
//  d[1]=0;
    while(q.size()){
        pii now=q.top();q.pop();
        int x=now.second;
//      D(x);D(-now.first);E;
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].from){
            int y=edge[i].to;
            ll w=edge[i].w;
            if(d[y]>w){
                deg[y]=1;
                d[y]=w;
                q.push(make_pair(-d[y],y));
            }
            else if(d[y]==w) deg[y]++;
            /*
            if(d[y]>d[x]+w){
                deg[y]=1,d[y]=d[x]+w;
                q.push(make_pair(-d[y],y));
            }
            else if(d[y]==d[x]+w) deg[y]++;
            */
        }
    }
}
void solve(){
    int ans=m+1;
//  for(int i=1;i<=n;i++) D(deg[i]);
//  E;
    for(int i=1;i<=n;i++) ans=min(ans,deg[i]);
    printf("%d\n",ans);
}
int main() {
//  ios::sync_with_stdio(false);
//  freopen("Roads.in","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        int from,to;
        ll w;
        for(int i=1;i<=m;i++) scanf("%d%d%lld",&from,&to,&w),add(from,to,w),add(to,from,w);
        dj(); 
        solve();
    }   
    return 0;
}

C
对两个数组分别求线性基,然后对这两个线性基求交,答案就是
代码如下

/*

*/
#define method_1
#ifdef method_1
/*

*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=50+5;
const int maxl=60+2;
const int INF=0x3f3f3f3f;
int n;
ll a[maxn],b[maxn],aa[3][maxl];
void init(){
    memset(aa[0],0,sizeof(aa[0]));
    memset(aa[1],0,sizeof(aa[1]));
    memset(aa[2],0,sizeof(aa[2]));
}
inline void insert(ll x,int cur) {
    for(int i=maxl-1; i>=0; --i) {
        if(x>>i) {
            if(!aa[cur][i]) {
                aa[cur][i]=x;
                break;
            }
            x^=aa[cur][i];
        }
    }
}
inline void Intersect(int x,int y) {
    ll t1[maxl],t2[maxl];
    for(int i=0; i=0; --j) {
                if(x>>j) {
                    if(!t1[j]) {
                        t1[j]=x,t2[j]=tp;
                        break;
                    }
                    x^=t1[j],tp^=t2[j];
                }
            }
            if(!x) insert(tp,2);
        }
    }
    
}
int main() {
    ios::sync_with_stdio(false);
    //freopen("Intersection.in","r",stdin);
    while(cin>>n){
        init();
        for(int i=1;i<=n;i++) cin>>a[i],insert(a[i],0);
        for(int i=1;i<=n;i++) cin>>b[i],insert(b[i],1);
//      for(int i=0; i

E
将选择区间转化为选择区间的两个端点,因此首先对a数组求一遍前缀和。然后将这n+1个数(包括第0个数)排序,从两头开始向中间取数即可。(因为绝对值的存在,所以不用考虑顺序)
代码如下

/*

*/
#define method_1
#ifdef method_1
/*

*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=1e5+5;
const int INF=0x3f3f3f3f;
int n,m;
ll C,a[maxn],b[maxn];
ll ans;
void init(){
    ans=0;
}
int main() {
    ios::sync_with_stdio(false);
    //freopen("Partial Sum.in","r",stdin);
    while(scanf("%d%d%lld",&n,&m,&C)!=EOF){
        init();
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
        sort(a,a+n+1);
        for(int i=0,j=n,cnt=1;i

H
找出树的直径上的两个端点a和b(3遍dfs),然后将每个点和两个端点中较远的点连起来即可。
代码如下

/*
找出树的直径上的两个端点a和b(3遍dfs),然后将每个点和两个端点中较远的点连起来即可。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=1e5+5;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,m;
struct node {
    int from,to;
    ll w;
} edge[maxn<<1];
queueq;
int t,head[maxn],tot; 
ll ans;
ll d1[maxn],d2[maxn];
void init(){
    memset(head,0,sizeof(head));
    tot=1;
}
void add(int u,int v,ll w) {
    edge[++tot].to=v;edge[tot].from=head[u];edge[tot].w=w;head[u]=tot;
}
void dfs(int x,int fa,ll d){
    d1[x]=d;
    for(int i=head[x];i;i=edge[i].from){
        int y=edge[i].to;
        ll w=edge[i].w;
        if(y==fa) continue;
        dfs(y,x,d+w);
    }
}
int main() {
//  ios::sync_with_stdio(false);
    //freopen("Highway.in","r",stdin);
    while(scanf("%d",&n)!=EOF){
        init();
        int from,to;
        ll w;
        for(int i=1;i<=n-1;i++) scanf("%d%d%lld",&from,&to,&w),add(from,to,w),add(to,from,w);
        dfs(1,0,0);
        int a=max_element(d1+1,d1+n+1)-d1;
//      for(int i=1;i<=n;i++) D(d1[i]);
//      E;
        dfs(a,0,0);
        int b=max_element(d1+1,d1+n+1)-d1;
//      for(int i=1;i<=n;i++) D(d1[i]);
//      E;
        memcpy(d2,d1,sizeof(d1));
        dfs(b,0,0);
//      for(int i=1;i<=n;i++) D(d1[i]);
//      E;
        ans=-d1[a];
        for(int i=1;i<=n;i++){
            ans+=max(d1[i],d2[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

I
考虑一个性质,对于任意正整数n和m,总能找到。因此,为了让结果f(t)尽量小,就需要让i和j取到上式中的a和b。于是所求的答案就是这个数的中间值,即
如果觉得上面的话过于抽象,那么那样例具体解释下。
例如n=1,m=2时,lcm(n,m)=2。那么对于i、j,能取到的值就是0、1/2、1...
这之间最小的间距就是1/2,所以当t为1/4时,无论i和j怎么调整,答案都不会小于1/4。
代码如下

/*

*/
#define method_1
#ifdef method_1
/*

*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=5+5;
const int INF=0x3f3f3f3f;
ll n,m,a[maxn];
ll gcd(ll a,ll b){
    return !b?a:gcd(b,a%b);
}
void solve(){
    ll d=gcd(n,m);
    ll lcm=n*m/d;
    cout<<1<<"/"<>n>>m){
        solve();    
    }
    return 0;
}
#endif
#ifdef method_2
/*

*/

#endif
#ifdef method_3
/*

*/

#endif

你可能感兴趣的:(2019牛客国庆集训派对day4)