“网宿科技杯”厦门大学第四届程序设计积分赛 热身赛

/*

A 题 
题意:中文 
解题:此题果断二分,时间复杂度为 n*lgn ,注意最后的结果是 min ,理解其意 

*/
#include<iostream>  
#include<cstdio>  
#include<string>  
#include<algorithm>  
#define manx 100009  
using namespace std;  
  
long long a[manx];  
  
int main(){  
    int n;  
    while(scanf("%d",&n)!=EOF){  
        long long min=2000000009,max=0,sum=0;  
        for(int i=1;i<=n;i++){  
            scanf("%lld",&a[i]);  
            if(min>a[i]) min=a[i];  
            if(max<a[i]) max=a[i];  
        }  
        long long mid=(max+min)>>1,flag=0;  
          
        while(max>min){  
            sum=0; flag=0;  
            mid=(max+min)>>1;  
            for(int i=1;i<=n;i++){  
                if(sum+mid<a[i]) { flag=1; break; }  
                sum=sum+mid-a[i];  
            }  
            if(flag){  
                min=mid+1; continue;  
            }  
            max=mid;  
        }  
        printf("%lld\n",min);  
    }  
}

 

/*

D 题 
这道题想了我不知道多久了,一下午 + 一晚上 + 一上午,尼玛啊,总算是找到规律了。。
方法总结:找每个点的必败点,也就是找最大的菱形,然后计算对点的步数。。 

*/
#include<iostream>
#include<cstdio>
#include<algorithm> 
using namespace std;
int main(){
    int n,m ;
    while(cin>>n>>m){
        if(n==m){
            if(n%3==2)cout<<"Alice"<<endl;
            else cout<<"Bob"<<endl;
            continue;
        } 
        int k=min(n,m);
        if(k%3==0) cout<<"Bob"<<endl;
        else cout<<"Alice"<<endl;
    }
}


 

/*

E题, 题意:中文 
此题就是一道裸的KMP模板题 

*/
#include<iostream>  
#include<cstdio>  
#include<string>  
#define manx 100009  
using namespace std;  
char a[manx*2],b[manx];  
int n,m,next[manx];  
void get_next(){   求next的值   
    int i=1,j=0;  
    next[1]=0;    固定的值初始化 next[2]=1;   
    while(i<m){    
        if(j==0||b[i]==b[i]){  
            ++i,++j;  
            next[i]=j;  这里是递推关系   
        }  
        else j=next[j];   注意了 这里是重点 ,采用了记忆化   
    }  
}  
  
int kmp(){  
    int i=1,j=1;  
    while(i<=n&&j<=m){  /// 匹配限制条件   
        if(j==0||a[i]==b[j]){ /// 匹配成立条件   
            ++i;++j;  
        }  
        else j=next[j];  /// 转换,,思想真的要严老师讲了才知道   
    }  
    if(j>m) return i-m;  
    return 0;  
}  
  
int main(){  
    while(cin>>a+1>>b+1){  
        n=strlen(a+1);          
        m=strlen(b+1);  
        if(!strcmp(a+1,b+1)){ printf("0\n"); continue;}  
        int k=n;  
        for(int i=n+1,j=1;i<=n+n && j<=n;i++,j++)  
            a[i]=a[j];  
        n=n+n;  
        get_next();  
        int flag=kmp();  
        if(!flag) printf("-1\n");      
        else printf("%d\n",k-flag+1);  
    }  
}  


/*

C题,裸的线段树,只是要维护几个节点的值。。。 

*/
#include<iostream>  
#include<cstdio>  
#include<algorithm>  
using namespace std;  
#define manx 100100  
#define lson l,mid,rt<<1  
#define rson mid+1,r,rt<<1|1  
long long root[manx*4],x[manx],sum[manx*4],ans[manx*4],flag,val;  
  
void make(int l,int r,int rt){  
    if(l==r) { root[rt]=x[l]; sum[rt]=x[l]; ans[rt]=x[l]; return ; }  
    int mid=(l+r)>>1;  
    make(lson);  
    make(rson);  
    root[rt]=root[rt<<1] & root[(rt<<1)|1];  
    sum[rt]=sum[rt<<1] ^ sum[(rt<<1)|1];  
    ans[rt]=ans[rt<<1] | ans[(rt<<1)|1];  
}  
  
void query(char s,int ll,int rr,int l,int r,int rt){  
    if(ll<=l && rr>=r){    
        if(!flag){  
            if(s=='a') val=root[rt];  
            if(s=='x') val=sum[rt];  
            if(s=='o') val=ans[rt];  
            flag=1;   
        }        
        else{  
            if(s=='a') val=val & root[rt];  
            if(s=='x') val=val ^ sum[rt];  
            if(s=='o') val=val | ans[rt];  
        }      
        return ;  
    }  
    int mid = (l+r)>>1;  
    if(rr<=mid) query(s,ll,rr,lson);  
    else if(ll>mid) query(s,ll,rr,rson);  
    else {  
        query(s,ll,rr,lson);  
        query(s,ll,rr,rson);  
    }      
}  
  
int main(){  
    int n,m;  
    while(cin>>n>>m){  
        for(int i=1;i<=n;i++)  
            scanf("%lld",&x[i]);  
        make(1,n,1);  
        char s[4];  
        int l,r;  
        for(int i=0;i<m;i++){  
            val=0; flag=0;  
            scanf("%s %d %d",s,&l,&r);  
            query(s[0],l,r,1,n,1);  
            printf("%lld\n",val);  
        }  
    }  
}  


/*

F 题,建树
解题:先把每个元素看成一个单个集合,然后找出一个大集合作为主集合,
每次找出一个大集合,然后进行合并 。。。 

*/
#include<iostream>
#include<algorithm>
using namespace std;
#define manx 20

int x[manx],s[manx],pre[manx];
int n,ans;

int judge(){  ///判断树是否建成 
    for(int i=1;i<=n;i++)
        if(x[i]) return 1;
    return 0;
}

int query(){ /// 找出大集合 
    int max=0,ans;
    for(int i=1;i<=n;i++){
        if(s[i]) continue;
        if(max<x[i]) max=x[i],ans=i;
    }
    return ans;
}

void fan(int pos){ /// 进行合并 
    for(int i=1;i<=n;i++){
        if(s[i] && x[i]){
            x[i]--;
            x[pos]--;
            s[pos]=1;
            pre[pos]=i;
            return ;
        }
    }
}

int main(){
    while(cin>>n){
        int max=0;
        for(int i=1;i<=n;i++){
            s[i]=0;  pre[i]=i;
            cin>>x[i];
            if(x[i]>max) max=x[i],ans=i;
        }
        s[ans]=1;
        while(judge()){
            int pos=query();
            fan(pos); 
        }
        for(int i=1;i<=n;i++){
            if(pre[i]==i) continue;
            cout<<i<<" "<<pre[i]<<endl;
        }
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值