czl蒻蒟的OI之路7

  • XJOI奋斗群蒻蒟群群赛8 RANK排名
      • T1k-Factorization RE一次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T2Odd sumWA一次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T3Minimal string已AC
          • 题意
          • 分析过程
          • 给出题解
      • T4Broken BST
          • 题意
          • 分析过程
          • 给出题解
      • T5Array Queries
          • 题意
          • 分析过程
          • 给出题解
      • T6Mice and Holes
          • 题意
          • 分析过程
          • 给出题解
      • 蒻蒟的总结

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

T1:k-Factorization (RE一次后AC)

题意:

给你两个数n和k,让你把n分成k个数相乘(乘数中不能有1),如果不能的话就输出-1。可以的话就把乘数都输出。

分析过程:

既然乘数不能有1,并且还要刚好分到k个,所以前面k-1个数字尽量是较小的k的因数,最后一个数再输出n除以前面的数的值。但是在这部运行前要有一些特判,如果pow(2,k)>n(即就算全部都用2拆分,都会达不到k),就直接输出-1。如果k等于1,就直接输出n。有了这些特判之后,在进行拆分,拆分时都用质数去试,这样能节省很多时间。同时还要注意如果拆分到最后一个是1,也是要输出-1的。

给出题解:
#include
using namespace std;

int pre[2000];

bool prime(int n)
{
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)return false;
    }
    return true;
}

void get_pre()
{
    int j=2;
    for(int i=3;i<=1000;i++)
    {
        if(prime(i)==true)pre[j]=i,j++;
    }
}
int main()
{
    int n,k,x=1;
    long long ans;
    cin>>n>>k;
    ans=pow(2,k);
    if(ans>n)cout<<-1<else if(k==1)cout<else 
    {
    pre[1]=2;
    int print[100]={0};
    get_pre();
    if(prime(n)==true)cout<<-1<else
    {
        int a=k;
        for(int i=1;i&&k!=1;i++)
        {
            if(n%pre[i]==0)
            {
                print[x]=pre[i];
                n=n/pre[i];
                i--;
                x++;
                k--;
                if(n==1&&k!=0){cout<<-1<return 0; }
            }

        }
    for(int i=1;icout<" ";
    }
    cout<return 0;
}

T2:Odd sum(WA一次后AC)

题意:

给你一个数列,求数列中的一些数加起来的值为奇数,输出这个奇数的最大值。

分析过程:

这个数列中的数,有正数,也有负数。在计算这个最大值的时候,可以先把正数和负数分成两堆,先计算正数的所有数的和,判断是否是奇数。如果是奇数,就直接输出这个值(因为加上负数也只会变小)。如果是偶数,就分别把数列中最小的正奇数a和最大的负奇数b拉出来比较。如果找不到这个a或b,就用原值加上b或减去a。如果找到这两个数了,就比较两个数的绝对值大小。如果a大,就用原值加上b,反之则减去a。这样求得的就是最大值。

给出题解:
#include
using namespace std;

int zh[100050],fu[100050],a[100050];

bool ji(int a)
{
    a=abs(a);
    if(a%2==1)return true;
    return false;
}

int main()
{
//  freopen("in.txt","r",stdin);
    long int n,ans=0;       
    int j=1,k=1;
    int cntz=0,cntf=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(a[i]>=0)
        {
            zh[j]=a[i];
            cntz++;
            ans=ans+zh[j];
            j++;
        }
        else 
        {
            fu[k]=a[i];
            cntf++;
            k++;
        }
    }
    sort(zh+1,zh+1+cntz);
    sort(fu+1,fu+1+cntf);
//  cout<
    if(ans%2==1)cout<else 
    {
        int a=0,b=0;
        for(int i=cntf;i>=1;i--)
        {
            if(ji(fu[i])==true)
            {
                a=fu[i];
                break;
            }
        }
        for(int i=1;i<=cntz;i++)
        {
            if(ji(zh[i])==true)
            {
                b=zh[i];
                break;
            }
        }
//      cout<
        if(b==0)cout<else if(a==0)cout<else 
        {
         if(abs(a)>=b)cout<else cout<

T3:Minimal string(已AC)

题意:

有一个字符串s,还有两个空的字符串t、u,可以有两个操作:1、把s的的一个字母放到t中。2、把t的最后一个字母放到u中。要求使得u最后的字符串字典序最小。

分析过程:

只要发现了这题中的字母是后进先出,就能发现这是一个栈的运用。所以只需要开一个栈,然后往栈中输入。如果输入的字母比栈顶的字母要小,就保留,如果比栈顶大 ,就直接弹出。这样输出的字符串字典序便是最小的。

给出题解:
#include
using namespace std;

    char ss[100800];
    int a[100800];
    int m[100800];
int main()
{
    cin>>ss;
    int n=strlen(ss);
    memset(m,0,sizeof(m));
    for(int i=0; i96;
    for(int i=n-1; i>=0; i--)
    {
        if(i==n-1)m[i]=a[i];
        else m[i]=min(m[i+1],a[i]);
//      cout<
    }
    stack<char>s;
    for(int i=0; iif(s.size()==0)
        {
            s.push(ss[i]);
        }
        else
        {
            while(!s.empty())
            {
                int ding=s.top()-96;
                if(ding<=m[i])
                {
                    cout<else break;
            }
            s.push(ss[i]);
        }
    }
    while(!s.empty())
    {
        cout<

T4:Broken BST

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

T5:Array Queries

题意:

给出一个n个数的数列a(a<=n),然后给你两个数k和p,让你计算ap+p+k的值,如果这个值小于等于n,就继续执行这个命令,直到它大于n。让你求执行命令的次数。

分析过程:

如果用暴力求解,那么当k比较小的时候,这个命令的执行次数会变得很大,会TLE。所以我们可以用记忆化搜索,先预先处理k<=300的执行次数,然后如果输入次数小于300,就可以直接输出数据,其余的就可以直接暴力运算。

给出题解:
#include
using namespace std;
const int maxn=1e5+10;
int dp[305][maxn];
int main()
{
    int n,a[maxn];
    int p,k;
    int q;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>a[i];
    }
    cin>>q;
    for(int j=1; j<=300; j++)
    {
        for(int i=n; i>=1; i--)
        {
            if(i+a[i]+j>n) dp[j][i]=1;
            else
            {
                dp[j][i]=dp[j][i+a[i]+j]+1;
            }
        }
    }
    for(int i=1; i<=q; i++)
    {
        cin>>p>>k;
        int cnt=0;
        if(k<=300)
        {
            cout<else
        {
            while(p<=n)
            {
                p=p+a[p]+k;
                cnt++;
            }
            cout<return 0;
}

T6:Mice and Holes

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

蒻蒟的总结:

这是前天的题目,有三道题没有做出来,剩下的3题也是拼死才订正出来一题,表示时间真的有点紧张了。昨天还有动态规划专题,所以时间很少。不过并不是说不会补了,这些题都是我的弱处,要抓紧攻克它。
继续贴出吴老师的话:学信息的人永不服输!!!

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