NYOJ Practice-Round#2(题解)

   A .你怎么又插队      题目链接:http://acm.nyist.me/JudgeOnline/problem.php?id=2351

 题意:n个人初始从1到n排队,q次变动,每次让编号为id的人排到pos位置,其他人的相对位置不变。

问你经过q次变动后的队列是什么样子。。

 题解:对于每一个人初始的id,让他乘上一个数(这个数尽可能大于总人数),使得让这个人拥有一个权值,

每次变动时,只需让这个人的权值变为pos*(之前定义的数)-t(t从1开始),为什么要减t,别忘了,假如你放到pos位置,等于说之前在pos位置上的人不是要往后移一位了,但是你又不能影响前边的人,这里就体现出来给每个人权值的作用了,一个位置的权值的变化范围是(p*(i-1),p*i ],p是操作次数,最后排个序从前往后输出即可。

#include<map>    
#include<stack>    
#include<queue>  
#include<vector>    
#include<math.h>    
#include<stdio.h>  
#include<iostream>
#include<string.h>    
#include<stdlib.h>    
#include<algorithm>    
using namespace std;    
typedef long long  ll;    
#define inf 1000000000    
#define  mod 1000000007   
#define  maxn  1000060
#define  lowbit(x) (x&-x)    
#define  eps 1e-10   
struct node
{
    ll id,val;
}a[maxn];
ll score[maxn];
bool comp(node a,node b)
{
    return a.val<b.val;
}
int  main(void)
{
    ll n,p,i,m=1000100,id,pos;
    while(scanf("%lld%lld",&n,&p)!=EOF)
    {
        for(i=1;i<=n;i++)
            score[i]=i*m;
        ll tmp=1;
        while(p--)
        {
            scanf("%lld%lld",&id,&pos);
            score[id]=pos*m-tmp;
            tmp++;
        }
        for(i=1;i<=n;i++)
        {
            a[i].id=i;
            a[i].val=score[i];
        }
        sort(a+1,a+n+1,comp);
        for(i=1;i<=n;i++)
            printf("%lld ",a[i].id);
        printf("\n");
    }
    return 0;
}

方法二:可以先将改动的信息存下来,从后往前队列,因为最后一次变动的人的位置是确定的。。。。

#include<map>    
#include<stack>    
#include<queue>  
#include<vector>    
#include<math.h>    
#include<stdio.h>  
#include<iostream>
#include<string.h>    
#include<stdlib.h>    
#include<algorithm>    
using namespace std;    
typedef long long  ll;    
#define inf 1000000000    
#define  mod 1000000007   
#define  maxn  1000060
#define  lowbit(x) (x&-x)    
#define  eps 1e-10   
struct node
{
    int id,pos;
}a[maxn];
int vis[maxn];
vector<int>q[maxn];
int main(void)
{
    int n,p,i,j;
    while(scanf("%d%d",&n,&p)!=EOF)
    {
        for(i=1;i<=n;i++)
            q[i].clear();
        memset(vis,0,sizeof(vis));
        for(i=1;i<=p;i++)
            scanf("%d%d",&a[i].id,&a[i].pos);
        for(i=p;i>0;i--)
        {
            int id=a[i].id;
            if(vis[id]==0)
            {
                int v=a[i].pos;
                q[v].push_back(id);
                vis[id]=1;
            }
        }
        for(i=1;i<=n;i++)
            if(vis[i]==0)
                q[i].push_back(i);
        for(i=1;i<=n;i++)
            for(j=0;j<q[i].size();j++)
                printf("%d ",q[i][j]);
        printf("\n");
    }
    return 0;
}

B.盖伦的告白        题目链接:http://acm.nyist.me/JudgeOnline/problem.php?id=2344

题意:见题面吧,不多解释了23333

题解:一道挺经典的题了,首先很容易想到,如果去掉中间的某一个数,则最大值只会更大,因此这里就要简单贪心一下了,每次取两端的某一个数就好啦,然后线段树查询下区间最大值就OK了。。

#include<map>    
#include<stack>    
#include<queue>  
#include<vector>    
#include<math.h>    
#include<stdio.h>  
#include<iostream>
#include<string.h>    
#include<stdlib.h>    
#include<algorithm>    
using namespace std;    
typedef long long  ll;    
#define inf 1000000000    
#define  mod 1000000007   
#define  maxn  1000060
#define  lowbit(x) (x&-x)    
#define  eps 1e-10   
ll a[maxn],b[maxn];
void build(int id,int l,int r)
{
    if(l==r)
    {
        a[id]=b[l+1]-b[l];
        return;
    }
    int m=(l+r)/2;
    build(id*2,l,m);
    build(id*2+1,m+1,r);
    a[id]=max(a[id*2],a[id*2+1]);
}
ll query(int id,int l,int r,int aa,int bb)
{
    if(l>=aa && r<=bb)
        return a[id];
    ll res=0,m=(l+r)/2;
    if(aa<=m)
        res=max(res,query(id*2,l,m,aa,bb));
    if(bb>m)
        res=max(res,query(id*2+1,m+1,r,aa,bb));
    return res;
}
int  main(void)
{
    ll ans;
    int n,k,i,len;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        ans=1000000000;
        for(i=1;i<=n;i++)
            scanf("%lld",&b[i]);
        build(1,1,n-1);
        len=n-k-1;
        for(i=1;i+len<=n;i++)
            ans=min(ans,query(1,1,n-1,i,i+len-1));
        printf("%lld\n",ans);
    }
    return 0;
}


C.A problem is so  easy      题目链接:http://acm.nyist.me/JudgeOnline/problem.php?cid=1012&pid=2

题意:给你n个数的数组,找出异或值为正整数的所有子区间中长度最长的那个。

题解:我的方法是枚举二进制的每一位,贪心思想,最大值肯定在两端找,因为是要长度为奇数

很好办,记一下前缀和,(1)拿尾的偶减去头的奇(2)尾的奇。从中找出最大值并保存,感觉写麻烦了。。

#include<map>    
#include<stack>    
#include<queue>    
#include<vector>    
#include<math.h>    
#include<stdio.h>    
#include<iostream>    
#include<string.h>    
#include<stdlib.h>    
#include<algorithm>    
using namespace std;    
typedef long long  ll;    
#define inf 1000000000    
#define mod 1000000007   
#define  maxn  1000060
#define  lowbit(x) (x&-x)    
#define  eps 1e-10    
ll a[maxn],b[maxn];
int  main(void)
{
    ll n,i,j,ans;
    while(scanf("%lld",&n)!=EOF)
    {
        ll maxs=-1;ans=0;
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            maxs=max(maxs,a[i]);
        }
        if(maxs==0)
        {
            printf("0\n");
            continue;
        }
        for(i=0;i<64;i++)
        {
            if((1<<i)>maxs)
                    break;
            ll tmp=0,p=-1,q=-1,p1=-1,q1=-1;
            for(j=1;j<=n;j++)
            {
                if(a[j]&(1<<i))
                    b[j]=b[j-1]+1;
                else
                    b[j]=b[j-1];
            }
            for(j=1;j<=n;j++)
            {
                if(b[j]%2 && p==-1)
                    p=j;
                if(b[j]%2==0 && q==-1)
                    q=j;
                if(p>=0 && q>=0)
                    break;
            }
            for(j=n;j>0;j--)
            {
                if(b[j]%2 && p1==-1)
                    p1=j;
                if(b[j]%2==0 && q1==-1)
                    q1=j;
                if(p1>=0 && q1>=0)
                    break;
            }
            ans=max(ans,p1);
            ans=max(ans,q1-p);
            for(j=1;j<=n;j++)
                b[j]=0;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

D.彩排    题目链接:http://acm.nyist.me/JudgeOnline/problem.php?id=2350

题意:很简单,见体面吧2333。

题解:很sb的一道题,但是比赛是给的内存大小把我给唬住了,其实是一道卡内存的题,也就是数组的大小不能超过100,然而我比赛是开了有n这么大,但是OJ返回的结果是wa,我以为没超内存,然后就。。。。如果不开这么大数组的话,呢我们可以转化为二进制做,按位统计1的个数,最后将每一位中1的个数不能被k整除加到答案中即可。

#include<map>    
#include<stack>    
#include<queue>  
#include<vector>    
#include<math.h>    
#include<stdio.h>  
#include<iostream>
#include<string.h>    
#include<stdlib.h>    
#include<algorithm>    
using namespace std;    
typedef long long  ll;    
#define inf 1000000000    
#define  mod 1000000007   
#define  maxn  1000060
#define  lowbit(x) (x&-x)    
#define  eps 1e-10  
int a[32];
int  main(void)
{
    int n,k,i,ans,x,tmp;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        ans=0;tmp=n;
        memset(a,0,sizeof(a));
        while(tmp--)
        {
            scanf("%d",&x);
            i=0;
            while(x)
            {
                a[i]=a[i]+x%2;
                x/=2;
                i++;
            }
        }
        for(i=0;i<33;i++)
            if(a[i]%k)
                ans=(ans|(1<<i));
        printf("%d\n",ans);
    }
    return 0;
}

E. LYQ的字符串       题目链接:http://acm.nyist.me/JudgeOnline/problem.php?id=2347

题意:一个字符串如果其所有长度为奇数的子串都是回文串那么就称这个字符串是奇回文串。

给你一个长度为N的字符串,假如让你最多可以修改k个字符,你的目标是求出最长的奇回文子串

题解:根据题意的描述,这个字串中对于任何的i,都符合Ai=Ai+2.所以奇数位上的字符都相同,偶数位同理。如果有一个子串两个条件都满足那么这个子串就可以当做答案之一了,但是可以修改k个字符,答案还可以贪心增长。我们单独考虑奇偶位上的字符,最优策略当然是保留出现次数最多的那个,我们可以用两点法,每一步都找两种情况中出现频率最多的字符,这个可以用26*2的数组来统计,遍历一遍找出最优解即可。

#include<map>    
#include<stack>    
#include<queue>    
#include<vector>    
#include<math.h>    
#include<stdio.h>    
#include<iostream>    
#include<string.h>    
#include<stdlib.h>    
#include<algorithm>    
using namespace std;    
typedef long long  ll;    
#define inf 1000000000    
#define mod 1000000007   
#define  maxn  100600  
#define  lowbit(x) (x&-x)    
#define  eps 1e-10    
char s[maxn];
int dp[maxn][2];
int main(void)
{
    int k,i,ans,h;
    while(scanf("%d",&k)!=EOF)
    {
        ans=0;
        scanf("%s",s);
        memset(dp,0,sizeof(dp));
        int len=strlen(s),ji,ou,j=0;
        for(i=0;i<len;i++)
        {
            if(i>0)
                dp[s[i-1]-'a'][(i-1)&1]--;
            ji=0;ou=0;
            for(h=0;h<26;h++)
            {
                ji=max(ji,dp[h][1]);
                ou=max(ou,dp[h][0]);
            }
            int num=j-i-ji-ou;                              
            while(num<=k && j<len)
            {
                dp[s[j]-'a'][j&1]++;
                ji=max(ji,dp[s[j]-'a'][1]);
                ou=max(ou,dp[s[j]-'a'][0]);
                j++;
                num=j-i-ou-ji;
                if(j-i>ans && num<=k)
                    ans=j-i;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值