czl蒻蒟的OI之路14、15

  • XJOI奋斗群蒻蒟群群赛15 RANK排名9
      • T1Fashion in Berland 已AC
          • 题意
          • 分析过程
          • 给出题解
      • T2s-palindrome WA四次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T3Exponential notation WA三次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T4Swaps in PermutationWA两次之后AC
          • 题意
          • 分析过程
          • 给出题解
      • T5Xor-sequences
          • 题意
          • 分析过程
          • 给出题解
      • T6Couple Cover WA一次后AC
          • 题意
          • 分析过程
          • 给出题解
  • XJOI奋斗群蒻蒟群群赛16 RANK排名9
      • T1Bus已AC
          • 题意
          • 分析过程
          • 给出题解
      • T2Make a Permutation 已AC
          • 题意
          • 分析过程
          • 给出题解
      • T3Fire WA三次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T4Marvolo Gaunts Ring WA两次之后AC
          • 题意
          • 分析过程
          • 给出题解
      • T5Helga Hufflepuffs Cup
          • 题意
          • 分析过程
          • 给出题解
      • T6Salazar Slytherins Locket
          • 题意
          • 分析过程
          • 给出题解
      • 蒻蒟的总结

—>XJOI奋斗群(蒻蒟群)群赛15<— RANK排名9

T1:Fashion in Berland (已AC)

题意:

给你一个数列,问你这个数列里是否只有一个0并且,仅有一个数时,这个数是不是1。

分析过程:

典型的水题,不多说。。

给出题解:
#include
using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    int a[10005];
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]==0)cnt++;
    }
    if(n==1)
    {
        if(a[1]==1)printf("YES");
        else printf("NO");
    }
    else 
    {
        if(cnt==1)printf("YES");
        else printf("NO");
    }
    return 0;
}

T2:s-palindrome (WA四次后AC)

题意:

给你一个字符串,问你这个字符串是不是对称的(不是回文,是真的对称)。

分析过程:

只需要先想好哪些字母和哪些字母是对称的(也可能和自己),然后一个个字母遍历过去就行了。

给出题解:
#include
using namespace std;

int main()
{
    string s;
    cin>>s;
    int n=s.length();
    bool flag=true;
    for(int i=0;n%2==0?i<=(n-1)/2:i<(n-1)/2;i++)
    {
//      printf("%d",i);
        if(s[i]=='A'&&s[n-i-1]=='A')continue;
        else if(s[i]=='b'&&s[n-i-1]=='d')continue;
        else if(s[i]=='d'&&s[n-i-1]=='b')continue;
        else if(s[i]=='H'&&s[n-i-1]=='H')continue;
        else if(s[i]=='I'&&s[n-i-1]=='I')continue;
        else if(s[i]=='M'&&s[n-i-1]=='M')continue;
        else if(s[i]=='O'&&s[n-i-1]=='O')continue;
        else if(s[i]=='o'&&s[n-i-1]=='o')continue;
        else if(s[i]=='p'&&s[n-i-1]=='q')continue;
        else if(s[i]=='q'&&s[n-i-1]=='p')continue;
        else if(s[i]=='T'&&s[n-i-1]=='T')continue;
        else if(s[i]=='U'&&s[n-i-1]=='U')continue;
        else if(s[i]=='V'&&s[n-i-1]=='V')continue;
        else if(s[i]=='v'&&s[n-i-1]=='v')continue;
        else if(s[i]=='W'&&s[n-i-1]=='W')continue;
        else if(s[i]=='w'&&s[n-i-1]=='w')continue;
        else if(s[i]=='X'&&s[n-i-1]=='X')continue;
        else if(s[i]=='x'&&s[n-i-1]=='x')continue;
        else if(s[i]=='Y'&&s[n-i-1]=='Y')continue;
        else 
        {
            flag=false;
//          printf("1");
            break;
        }
    }
    if(flag==true&&n%2==1)
    {
        if(s[n/2]=='A'||s[n/2]=='H'||s[n/2]=='I'||s[n/2]=='M'||s[n/2]=='O'||s[n/2]=='T'||s[n/2]=='U'||s[n/2]=='V'||s[n/2]=='W'||s[n/2]=='X'||s[n/2]=='Y'||s[n/2]=='o'||s[n/2]=='v'||s[n/2]=='w'||s[n/2]=='x')flag=true;
        else flag=false;
    }
    if(flag==true)printf("TAK");
    else printf("NIE");
    return 0;
} 

T3:Exponential notation (WA三次后AC)

题意:

给你一个数,让你把这个数变成科学计数法输出。

分析过程:

这题并不难,只要预先去掉前导零和末位的零,再改成科学计数法就行了。

给出题解:
#include
using namespace std;

int main()
{
    string s;
    cin>>s;
    int cnt=0;
    int pos=-1;
    bool flag=false;
    for(int i=0; i<s.length(); i++)
    {
        if(s[i]=='0'&&flag==false)continue;
        else if(s[i]=='0'&&flag==true)
        {
            cnt++;
        }
        else if(s[i]!=0&&s[i]!='.')
        {
            cnt++;
            flag=true;
        }
        if(s[i]=='.')
        {
            pos=i;
            break;
        }
    }
//  printf("%d\n",cnt);
    if(cnt==0)
    {
        int ans;
        int end;
        int start=0;
        for(int i=pos+1; i<s.length(); i++)
        {
            if(s[i]!='0')
            {
                end=i;
                if(start==0)start=i;
            }
        }
//      printf("%d %d\n",start,end);
        if(start!=end)
        {
            printf("%c.",s[start]);
            for(int i=start+1; i<=end; i++)
            {
                printf("%c",s[i]);
            }
            printf("E-%d",start-pos);
        }
        else
        {
            printf("%cE-%d",s[start],start-pos);
        }
    }
    else if(cnt==1&&pos!=-1)
    {
        bool zero=false;
        for(int i=pos+1; i<s.length(); i++)
        {
            if(s[i]!='0')
            {
                zero=true;
                break;
            }
        }
        if(zero==true)
        {
            printf("%c.",s[pos-1]);
            int end;
            for(int i=pos+1; i<s.length(); i++)
            {
                if(s[i]!='0')
                {
                    end=i;
                }
            }
//      printf("%d\n",end);
            for(int i=pos+1; i<=end; i++)
            {
                printf("%c",s[i]);
            }
        }
        else
        {
            printf("%c",s[pos-1]);
        }
    }
    else if(cnt>1&&pos!=-1)
    {
        int start=pos-cnt;
//      printf("%d\n",start);
        bool zero=false;
        int end1=-1;
        int end=-1;
        for(int i=start+1; i<pos; i++)
        {
            if(s[i]!='0')
            {
                zero=true;
                break;
            }
        }
        for(int i=start+1; i<pos; i++)
        {
            if(s[i]!='0')
            {
                end1=i;
            }
        }
        for(int i=pos+1; i<s.length(); i++)
        {
            if(s[i]!='0')
            {
                end=i;
            }
        }
//      printf("%d\n",end);
        if(zero==false&&end==-1)
        {
            printf("%cE%d",s[start],cnt-1);
        }
        if(zero==false&&end!=-1)
        {
            printf("%c.",s[start]);
            for(int i=start+1; i<pos; i++)
            {
                printf("%c",s[i]);
            }
            for(int i=pos+1; i<=end; i++)
            {
                printf("%c",s[i]);
            }
            printf("E%d",cnt-1);
        }
        else if(zero==true&&end!=-1)
        {
            printf("%c.",s[start]);
            for(int i=start+1; i<pos; i++)printf("%c",s[i]);
            for(int i=pos+1; i<=end; i++)printf("%c",s[i]);
            printf("E%d",cnt-1);
        }
        else if(zero==true&&end==-1)
        {
            printf("%c.",s[start]);
            for(int i=start+1; i<=end1; i++)printf("%c",s[i]);
            printf("E%d",cnt-1);
        }
    }
    else if(pos==-1)
    {
        bool zero=false;
        int start=-1;
        int end;
        for(int i=0; i<s.length(); i++)
        {
            if(s[i]!='0')
            {
                if(start==-1)start=i;
                end=i;
            }
        }
//      printf("%d %d\n",start,end);
        if(start!=end)
        {
            printf("%c.",s[start]);
            for(int i=start+1; i<=end; i++)
            {
                printf("%c",s[i]);
            }
            printf("E%d",s.length()-start-1);
        }
        else
        {
            if(start+1!=s.length())
                printf("%cE%d",s[start],s.length()-start-1);
            else printf("%c",s[start]);
        }
    }
    return 0;
}

T4:Swaps in Permutation(WA两次之后AC)

题意:

给出你一串数列,数列中的每一个数都是在1~n之间的,但可能有重复。有一些数可以和另一些数互换,让你在把一些数互换后,该数列字典序最大。

分析过程:

给出你的数之间的转化,可以做成一个并查集,然后把属于同一并查集的数存进优先队列中,从第一个数开始遍历,为了让字典序最大,就需要取出该数字所在优先队列中取出最大的数,并把该数弹出,由此重复下去。

给出题解:
#include 
using namespace std;
const int maxn = 1000005;
priority_queue<int> q[maxn];
int num[maxn];
int fa[maxn];
inline int find(int x)
{
    if(fa[x]==x)
        return x;
    else return fa[x]=find(fa[x]);
}
int main ()
{
    int n,m;
    cin >> n >>m;
    for(int i = 1 ; i <= n ; i ++)
    {
        scanf("%d",&num[i]);
        fa[i] = i;
    }
    for(int i = 0 ; i < m ; i ++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        fa[find(u)] = find(v);
    }
    for(int i = 1 ; i <= n ; i ++)
    {
        find(i);
        q[fa[i]].push(num[i]);
    }

    for(int i = 1 ; i <= n ; i ++)
    {
        printf("%d ",q[fa[i]].top());
        q[fa[i]].pop();
    }
    return 0;
}

T5:Xor-sequences

题意:
分析过程:
给出题解:

T6:Couple Cover (WA一次后AC)

题意:

简单来说,就是给你n个数,再给出你m个询问,问你在这个序列里乘机不小于这个数的对数有几对。

分析过程:

这题的数据比较大,如果一个一个搜过去的话,必然会TLE。所以我们可以先暴力预处理,处理1~300000中,数列中两两乘机不小于这些数的对数,询问时只需输出这个数即可。

给出题解:
#include
#define maxn 3000010

using namespace std;

long long n;
long long ask[maxn];
long long num[maxn];
int m;

int main()
{
    scanf("%d",&n);
    for (int i = 0; i < n; i++)
    {
        int a;
        scanf("%d",&a);
        ask[a]++;
    }

    for (int i = 1; i * i < maxn; i++)
    {
        for (int j = i; i * j < maxn; j++)
        {
            if (i == j)num[i * j] += ask[i] * (ask[i] - 1);
            else num[i * j] += 2 * ask[i] * ask[j];
        }
    }

    for (int i = maxn-2; i > 0; i--)
        num[i] += num[i+1];
    long long x = n * (n - 1) - num[1];
    scanf("%d",&m);
    while (m--)
    {
        int a;
        scanf("%d",&a);
        printf("%I64d\n", num[a] + x);
    }
}

—>XJOI奋斗群(蒻蒟群)群赛16<— RANK排名9

T1:Bus(已AC)

题意:

给出你四个数a,b,f,k,分别表示车子一段的目的地点、油箱的储油量、加油站的地点和旅行的次数,问你最少能够加多少次油能够到达旅行次数。

分析过程:

可以在中间的时候进行模拟,看经过一个加油站之后是否能够不加油并在下一次到达加油站,然后再特殊的判断一下回来的路程就行了。

给出题解:
#include
using namespace std;

int main()
{
    long long a,b,f,k;
    long long i;
    int res=0;
    scanf("%lld %lld %lld %lld",&a,&b,&f,&k);
    int jun=b-f;
    if(jun<0)
    {
        printf("-1");
        return 0;
    }
    for(i=2; i<=k; i++)
    {
        int oil;
        if(i%2==0)
            oil=2*(a-f);
        else
            oil=2*f;
        jun-=oil;
        if(jun<0)
        {
            res++;
            jun=b-oil;
        }
        if(jun<0)
        {
            printf("-1");
            return 0;
        }
    }
    int oil;
    if(k%2==0)
        oil=f;
    else
        oil=a-f;
    jun-=oil;
    if(jun<0)
    {
        res++;
        jun=b-oil;
    }
    if(jun<0)
    {
        printf("-1");
        return 0;
    }
    printf("%d",res);
    return 0;
}

T2:Make a Permutation! (已AC)

题意:

给你一个数列,让你输出用最小的步数,使数列为1~n没有重复的数据,并且字典序最大。

分析过程:

贪心算法,由于要使字典序最大,所以优先处理前面的数据,把取没有被取过的数最大的数,如此填下去,就能得出步数最少并且字典序最大的数列。

给出题解:
#include
int n,k=1;
bool vis[200100];
int a[200100],pos[200100],print[200100];
int cnt=0;
int main()
{
    int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[a[i]]++;
    }
    for(i=1;i<=n;i++)
    {
        while(pos[k]>0) k++;
        if(pos[a[i]]==1)
        {
            if(vis[a[i]]==false)
                print[i]=a[i];
            else
                print[i]=k++,cnt++;
        }
        else
        {
            if(vis[a[i]]==true||kprint[i]=k++,cnt++;
            else
                print[i]=a[i],vis[a[i]]=true;
            pos[a[i]]--;
        }
    }
    printf("%d\n",cnt);
    for(i=1;i<=n;i++)printf("%d ",print[i]);
    return 0;
}

T3:Fire (WA三次后AC)

题意:

给你n个物品,每个物品有一个抢救的时间、最晚抢救时间和价值,当时间大于等于该物品的最晚抢救时间的时候,这个物品就会被烧毁,问你最多能够抢救出来价值为多少的东西。

分析过程:

这题是一道背包题,只需要稍稍做一些调整,先把最晚抢救时间从小到大进行排序,然后就是简单的dp了,只不过当时间小于该物品的抢救时间或者大于该物品的最晚抢救时间的时候,就可以直接continue了。

给出题解:
#include
#define N 2010
using namespace std;
struct fire
{
    int t,d,p,x;
} a[N];
int dp[N][N],po[N][N],mx=0,maxp=0,maxn,n,print[N],cnt=0;
bool cmp(fire a,fire b)
{
    return a.dint x,int t)
{
    if (x==0) return;
    if (po[x][t]==t) answer(x-1,t);
    else print[++cnt]=a[x].x,answer(x-1,po[x][t]);
}

int main()
{
    scanf("%d",&n);
    for (int i=1; i<=n; ++i)
    {
        scanf("%d%d%d",&a[i].t,&a[i].d,&a[i].p);
        mx=max(mx,a[i].d);
        a[i].x=i;
    }

    sort(a+1,a+n+1,cmp);
    for (int i=1; i<=n; ++i)
        for (int j=0; j<=mx; ++j) dp[i][j]=-1;
    dp[0][0]=0;
    for (int i=1; i<=n; ++i)
    {
        for (int j=a[i].d-a[i].t-1; j>=0; --j)
            if (dp[i-1][j]!=-1)
                if (dp[i][j+a[i].t]1][j]+a[i].p)
                {
                    dp[i][j+a[i].t]=dp[i-1][j]+a[i].p;
                    po[i][j+a[i].t]=j;
                }
        for (int j=0; j<=mx; ++j)
            if (dp[i-1][j]>dp[i][j]&&dp[i-1][j]!=-1)
                dp[i][j]=dp[i-1][j],po[i][j]=j;
    }
    for (int i=1; i<=mx; ++i)
        if (dp[n][i]>maxp)maxp=dp[n][i],maxn=i;
    printf("%d\n",maxp);
    answer(n,maxn);
    printf("%d\n",cnt);
    for (int i=cnt; i>=1; --i)
        printf("%d ",print[i]);
}

T4:Marvolo Gaunt’s Ring (WA两次之后AC)

题意:

给你一串数列,再给你三个数p,q,r,让你在数列中选择三个数k1,k2,k3,(k1<=k2<=k3)使得p*k1+q*k2+r*k3的值最大,让你输出这个最大值。

分析过程:

可以同样的用到dp,分为三个阶段,第一个阶段求只考虑p的时候,求用到前i个数的时候最大的乘积的值,然后继续考虑q,求出用到前i个数的最大乘积之和,r也同样,最后输出dp[n]即可。

给出题解:
#include 
using namespace std;
#define inf 7e18
#define maxn 1000006
typedef long long LL;
LL num[maxn];
LL dp[maxn];

int main()
{

    int n;
    LL p,q,r;
    dp[0] = - inf;
    LL now,res = -inf;
    scanf("%d%lld%lld%lld",&n,&p,&q,&r);
    for(int i = 1; i <= n; ++i)
        cin >> num[i];

    for(int i = 1; i <= n; ++i)
    {
        now = p*num[i];
        dp[i] = max(dp[i-1],now);
    }

    for(int i = 1; i <= n; ++i)
    {
        now = q*num[i];
        dp[i] = max(dp[i-1],dp[i]+now);
    }

    for(int i = 1; i <= n; ++i)
    {
        now = r*num[i];
        dp[i] = max(dp[i-1],dp[i]+now);
        res = max(res,dp[i]);
    }
    printf("%lld\n",res);
    return 0;
}

T5:Helga Hufflepuff’s Cup

题意:
分析过程:
给出题解:

T6:Salazar Slytherin’s Locket

题意:
分析过程:
给出题解:

蒻蒟的总结:

这几天下来,题目的难度渐渐接近了NOIP的比赛了,一般的题目都是从cf上DIV.2上B题之后摘下来的了。感觉有一些题可能还是有点难以理解,这些可以留到十一的三天假期里继续学习。今天(9月27日)还去做了大佬班的题目,只有三题,总分300分,只有第一题AC了,分数比较低,但是欣慰的在于第2题大致的思路已经想到了,问题确实在于状态压缩的dp和矩阵乘法这些算法上。现在的我思维已经算是可以的了,但总是卡在一些算法题上,掌握的算法太少了。比如今天做的第三题,是一道线段树的题目,虽然NOIP并不不考线段树的问题,但是这也都不代表以后不考啊,所以之后看来要去恶补算法了。最后带上吴老师的一句话:如果你们只是抱着省一等奖的心得话,就不要让我叫你们了!(霸气!)。

你可能感兴趣的:(蒟蒻OI之路)