第十六届浙江省大学生程序设计竞赛

目录

 

B Element Swapping

E Sequence in the Pocket

F Abbreviation

G Lucky 7 in the Pocket

H Singing Everywhere

I Fibonacci in the Pocket

J Welcome Party

K Strings in the Pocket


B Element Swapping

【题意】已知交换前数列的x,y,该数列某两个位置互换后得到给定数列,根据x,y计算现数列由原序列交换位置的方案数。

【解题思路】推公式题。将原序列的x,y值设为x1,y1,现序列的x,y值设为x2,y2,设互换了p,q两个位置,易得以下两个等式dx=x2-x1=(p-q)(ap-aq)与dy=y2-y1=(p-q)(ap^2-aq^2),两式联立后易得dy=dx*(ap+aq),所以遍历一遍数组,对于每个树都能得到一个可以与她交换的数,再判断一下是否成立即可。对啦dx==0 &&dy==0的情况是只要数列中相同的数交换都可以,记得一定要特判,不然一直浮点错误。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
LL a[maxn],tot[maxn],c[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        LL x1=0,y1=0,x2=0,y2=0,ans=0;
        memset(tot,0,sizeof(tot));
        scanf("%d%lld%lld",&n,&x1,&y1);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            tot[a[i]]++;
            x2+=1LL*i*a[i];
            y2+=1LL*i*a[i]*a[i];
        }
        LL dx=x2-x1,dy=y2-y1;
        if(dx==0 && dy==0)
        {
            for(int i=1;i<=100000;i++)
            {
                if(tot[i]>1)
                    ans+=(tot[i]*(tot[i]-1))/2LL;
            }
        }
        else if(dx!=0 && dy!=0)
        {
            if(dy%dx==0)
            {
                LL p=dy/dx;
                for(int i=1;i<=n;i++)
                {
                    if(a[i]<p)
                    {
                        LL t=a[i]-(p-a[i]);
                        //printf("t=%lld\n",t);
                        if(t!=0 && dx%t==0)
                        {
                            int q=i-(dx/t);
                            if(q>i&& q<=n&&a[q]==p-a[i])ans++;
                        }
                    }
                }
            }
        }
        printf("%lld\n",ans);
    }
}

E Sequence in the Pocket

【题意】给一个长度为n的数组,每次操作可以把一个数放到最前面,问最少几次操作可以使这个数组变成非递减数列。

【解题思路】签到题,排序后倒序查找即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn],b[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int cnt=0,n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b,b+n);
        int t=n-1;
        for(int i=n-1;i>=0;i--)
        {
            if(a[i]==b[t])
            {
                t--;
                cnt++;
            }
        }
        printf("%d\n",n-cnt);
    }
}

F Abbreviation

【题意】除单词的首字母外,去除原因字母。

【解题思路】签到题。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char a[maxn],b[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        string s1,s2;
        cin>>s1;
        s2=s1[0];
        for(int i=1;i<s1.size();i++)
        {
            if(s1[i]=='a' ||s1[i]=='e'||s1[i]=='i' ||s1[i]=='y'||s1[i]=='o' ||s1[i]=='u')continue;
            s2=s2+s1[i];
        }
        cout<<s2<<endl;

    }
}

G Lucky 7 in the Pocket

【题意】找一个大于等于n的,能被7整除但不能被4整除的最小整数。n<=100。

【解题思路】签到题。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char a[maxn],b[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=n;i<=500;i++)
        {
            if(i%7==0 && i%4!=0)
            {
                printf("%d\n",i);
                break;
            }
        }
    }
}

H Singing Everywhere

【题意】给n个数,最多可以删去一个数使这个数列中的峰值出现次数最少。

【解题思路】签到题。先把峰值位置都找出来,分类讨论一下即可。

(1)当峰值位置只相隔1个位置时,且两个峰值一样大时,删去中间那个数达到最优,ans-2。

(2)其余只要判断一下前后的大小关系,最多只可能-1。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
long long a[maxn],b[maxn];
vector<int>v;
int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        v.clear();
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<n-1;i++)
        {
            if(a[i]>a[i-1] && a[i]>a[i+1])v.push_back(i);
        }
        int ans=v.size(),f=0;
        if(v.size()>=1)
        {
            for(int i=0;i<v.size()-1;i++)
            {
                if(v[i]+2==v[i+1])
                {
                    if(a[v[i]]==a[v[i+1]])
                    {
                        ans-=2;
                        f=1;
                        break;
                    }
                }
            }
            if(!f)
            {
                for(int i=0;i<v.size();i++)
                {
                    long long t1=a[v[i]-1],t2=a[v[i]],t3=a[v[i]+1];
                    //printf("t1=%lld t2=%lld t3=%lld\n",t1,t2,t3);
                    if(t1>t3)
                    {
                        if(v[i]-2>=0)
                        {
                            int t0=a[v[i]-2];
                            if(t0<t2)continue;
                            else
                            {
                                ans--;
                                break;
                            }
                        }
                        else
                        {
                            ans--;
                            break;
                        }
                    }
                    else if(t1<t3)
                    {
                        if(v[i]+2<n)
                        {
                            int t4=a[v[i]+2];
                            if(t4<t2)continue;
                            else
                            {
                                ans--;
                                break;
                            }
                        }
                        else
                        {
                            ans--;
                            break;
                        }
                    }
                    else
                    {
                        ans--;
                        break;
                    }
                }
            }
        }

        printf("%d\n",ans);
    }
}

I Fibonacci in the Pocket

【题意】求斐波那契数列的第a到第b项和为奇数还是偶数。

【解题思路】签到题。因为斐波那契数列的特征是奇 奇 偶 奇 奇 偶……即3的倍数即为偶数,所以只需要判断a和b被3除的情况即可。不需要大数,只需要将该数的每一位加起来除3即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char a[maxn],b[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s%s",a,b);
        int suma=0,sumb=0,la=strlen(a),lb=strlen(b);
        for(int i=0;i<la;i++)
            suma+=a[i]-'0';
        for(int i=0;i<lb;i++)
            sumb+=b[i]-'0';
        suma%=3;
        sumb%=3;
        if(suma==0)
        {
            if(sumb==0)printf("0\n");
            else if(sumb==1)printf("1\n");
            else if(sumb==2)printf("0\n");
        }
        else if(suma==1)
        {
            if(sumb==0)printf("0\n");
            else if(sumb==1)printf("1\n");
            else if(sumb==2)printf("0\n");
        }
        else
        {
            if(sumb==0)printf("1\n");
            else if(sumb==1)printf("0\n");
            else if(sumb==2)printf("1\n");
        }
    }
}

J Welcome Party

【题意】有n个人,m对朋友,如果某个人的一个朋友已经进去了,那么他就不会不开心,如果里面一个朋友都没有,他就会不开心,求最少的不开心人数以及进入的最小序列(然而比赛的时候读成一个人只有当它的所有朋友进去了他才会开心……)。

【解题思路】并查集找一下连通块,连通块个数即为答案,再用优先队列维护一下即可输出最小序列。(坑点是卡时间……)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int pre[maxn],vis[maxn],n,m,ans,ans1[maxn],tot;
vector<int>v[maxn];

int findroot(int x)
{
    return pre[x]==x?x:pre[x]=findroot(pre[x]);
}
void bfs()
{
    priority_queue<int,vector<int>,greater<int> >pq;
    for(int i=1;i<=n;i++)
    {
        if(pre[i]==i)
        {
            ans++;
            pq.push(i);
            vis[i]=1;
        }
    }
    while(!pq.empty())
    {
        int t=pq.top();
        pq.pop();
        ans1[tot++]=t;
        for(int i=0;i<v[t].size();i++)
        {
            if(!vis[v[t][i]])
            {
                pq.push(v[t][i]);
                vis[v[t][i]]=1;
            }
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ans=0;
        tot=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            pre[i]=i,v[i].clear(),vis[i]=0;
        while(m--)
        {
            int uu,vv;
            scanf("%d%d",&uu,&vv);
            v[uu].push_back(vv);
            v[vv].push_back(uu);
            int fa=findroot(uu);
            int fb=findroot(vv);
            if(fa!=fb)
            {
                if(fb<fa)pre[fa]=fb;
                else pre[fb]=fa;
            }
        }
        bfs();
        printf("%d\n",ans);
        printf("%d",ans1[0]);
        for(int i=1;i<tot;i++)
            printf(" %d",ans1[i]);
        printf("\n");
    }
}

K Strings in the Pocket

【题意】给一个字符串s和t,询问s的子串翻转后得到t的方案数。

【解题思路】当s和t相等时,需要用马拉车算法,马拉车算法用于求字符串的回文串,p[i]表示以位置i为中心的回文串的长度;当s和t不相等时,设置指针l和r,分别找到第一个s字符串和t字符串中s[l]和t[l]、s[r]和t[r]不等的位置,然后一直往外扩即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2e6+5;
LL p[maxn*2];
LL ans;
int len;
char s[maxn],tmp[maxn*2],t[maxn];
/*
void init()
{
    int len=2;
    ts[0]='$';
    ts[1]='#';
    for(int i=0;i<strlen(s);i++)
    {
        ts[len++]=s[i];
        ts[len++]='#';
    }
    ts[len]='\0';
}
void Manacher()
{
    init();
    int id,mx=0,len=strlen(ts);
    for(int i=1;i<len;i++)
    {
        if(i<mx)
            p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(ts[i-p[i]]==ts[i+p[i]])
            p[i]++;
        if(mx<i+p[i])
        {
            id=i;
            mx=i+p[i];
        }
        //printf("%d\n",p[i]);
        ans+=p[i]/2LL;
    }
}*/
void manacher()
{
    LL mx=0,pos=0;
    for(LL i=1;i<len;i++){
        if(i<mx) p[i]=min(p[2*pos-i],mx-i);
        else p[i]=1LL;
        while(tmp[i-p[i]]==tmp[i+p[i]]) p[i]++;
        if(mx<i+p[i]){
            pos=i;
            mx=i+p[i];
        }
    }
}
void init()
{
    tmp[0]='@'; tmp[1]='#';
    int j=2;
    for(int i=0;i<len;i++){
        tmp[j++]=s[i];
        tmp[j++]='#';
    }
    tmp[j]='\0';
    len=j;
    manacher();
    ans=0;
    for(int i=0;i<j;i++)
        ans+=p[i]/2LL;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        //memset(ts,0,sizeof(ts));
        ans=0;
        scanf("%s%s",t,s);
        len=strlen(s);
        if(strcmp(s,t)==0) init();
        else
        {
            int l=0,r=strlen(s)-1;

            while(s[l]==t[l])l++;
            while(s[r]==t[r])r--;
            int tl=l,tr=r;
            if(l<r)
            {
                while(s[tl]==t[tr])
                {
                    if(tr==l && tl==r)break;
                    tl++;tr--;
                }
                if(tr==l && tl==r)
                {
                    ans=1;
                    l--;
                    r++;
                    while(l>=0 && r<len && s[l]==t[r] && s[r]==t[l])
                    {
                        l--;
                        r++;
                        ans++;
                    }
                }
            }

        }
        printf("%lld\n",ans);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值