https://ac.nowcoder.com/acm/contest/5758
B:减成一

分析:
1.如果前面那个数比这个数大,那直接跳过,因为前面一个数可以带它躺成1。
2.如果前面那个数比这个数小,那区间是只能扩到前一个数这么大,因此还要进行多余的操作使自己变成1,于是产生了(a[i]-a[i-1])代价。
代码:

#include "bits/stdc++.h"
using namespace std ;
typedef long long ll;
ll t,n,sum;
ll a[100005];
int main(){
     cin>>t;
    while(t--){
       cin>>n;
       for(int i=1;i<=n;i++)
       {
           cin>>a[i];
           a[i]=a[i]-1;
        }
        sum=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]>=a[i-1]){
                sum+=a[i]-a[i-1];
            }
        }
        cout<<sum<<endl;
    }
    return 0;
}

c:面积

分析:
面积=正方形的面积x^2+两个圆面积23.14(a/2)^2
代码:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<set>
using namespace std;
typedef long long ll;
int i,j,cnt,n,k,t,b,m,ans;
using namespace std;
int main()
{
    scanf("%d",&t);
    while(t--){
        double x;
        scanf("%lf",&x);
        double r=x/2;
        printf("%.2lf\n",3.14*r*r*2+x*x);
    }

}

E:赛马

分析:
田忌赛马改编题,直接贪心即可。
如此贪心:
从我方大的马和敌方大的马开始比,如果我方的马大于敌方,则贡献值+1,换到对方下一匹马,换到我放下一匹马。
如果我方最大的马都输了,则换到对方下一匹马,我方不变。
大体上懂得取舍便可以了,详细分析可以百度田忌赛马贪心了解。
代码:

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
bool ran(int x,int y)
{
     return x<y;
}
int tj[1001],king[1001];
int main()
{
    int k,i,j,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&k);
        if(k==0) continue;
        memset(tj,0,sizeof(tj));
        memset(king,0,sizeof(king));
        for(i=0;i<k;i++) cin>>tj[i];
        for(i=0;i<k;i++) cin>>king[i];
        sort(tj,tj+k,ran);
        sort(king,king+k,ran);
        long int count=0;
        int tj_min=0,tj_max=k-1;
        int king_min=0,king_max=k-1;
        while(tj_min<=tj_max)
        {
            if(tj[tj_max]>king[king_max])
            {
                count++;
                tj_max--;king_max--;
            }
            else if(tj[tj_min]>king[king_min])
            {
                count++;
                tj_min++;king_min++;
            }
            else
            {
                // if(tj[tj_min]<king[king_max])
                // count--;
                tj_min++;king_max--;
            }   
        }
        cout<<count<<endl;
    }

    return 0;
}

F:三角形

分析:
三角形两边之和大于第三边,为了使得切割段数最多,我们由切割为1的片段开始,一开始为1,下个为1,再下个不能取1了,因为会组成三角形,所以我们取敲好不能组成三角形的最小片段2,然后2也不能取了,因为221会组成三角形,进而取3,于是我们发现每次取得的数恰好等于前面两个数的和,由此使得其恰好不能构成三角形,而112358这些数我们不难看出是斐波那契数列,由于斐波那契增长很快,从1开始枚举到总长度即可,记得开unsigned long long.
代码:

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
ll a[105];
int main(){

    int T;
    cin>>T;
    a[1]=1,a[2]=1;
    for(int i=3;i<=100;i++)
        a[i]=a[i-1]+a[i-2];
    while(T--){
        ll n;
        cin>>n;
        ll res=0;
        for(int i=1;i<=100;i++){
            if(a[i]>n) break;
            else n-=a[i],res++;
        }
        cout<<res<<endl;
    }
    return 0;
}

H:直线

分析:
结论题,答案为n*(n-1)/2
最优方案每条线都与其他的线相交,则每条线的贡献值为n-1,总共有n条线,同一根线算了两次。
数据范围要用大数,最好写个python,当然套用大数板子还是蛮舒服的。
代码:

#include "bits/stdc++.h"
using namespace std ;
typedef long long ll;
void reverse(char * c)
{
    int len = strlen(c);
    for(int i=0; i<len/2; i++)
        swap(c[i],c[len-i-1]);
}
void multiplication(char * srca,char * srcb,char * dest)//未翻转
{
    int ia,ib,c,
         na = strlen(srca),
         nb = strlen(srcb);
    reverse(srca);
    reverse(srcb);

    for(ia=0; ia<na; ia++)
    {
        c = 0;
        for(ib=0; ib<nb; ib++)
        {
            int t = (srca[ia]-48) * (srcb[ib]-48) + c,tt;
            if(dest[ia+ib]>47)
                tt = dest[ia+ib]-48 + t;
            else
                tt = t;
            dest[ia+ib] = tt%10 +48;
            c = tt/10;
        }// for

        while(c)    //处理进位,直到进位为0
        {
            int t;
            if(dest[ia+ib]>47)
                t = dest[ia+ib] - 48 + c;
            else
                t = c;
            dest[ia+ib++] = t%10 + 48;
            c /= 10;
        }// while

    }// for

        //将两个乘数和乘积都改为大端法
    reverse(dest);    
    reverse(srca);    
    reverse(srcb);    
}
void division(char * src,int n,char * dest)
{
    int len = strlen(src),
        i,                //计数
        k,                //商的下标
        t = 0,            //新的余数
        s = 0;            //余数
    bool flag = true;    //商是否有了第一个有效位,防止商首部一直出现0

    for(i=0,k=0; i<len; i++)
    {
        t = s*10+(src[i]-48);    //新余数
        if(t/n>0 || t==0)        //余数为0要修改商
            dest[k++] = t/n+48,s = t%n,flag = false;
        else                    //不够除,修改余数
        {
            s = t;
            if(!flag)            //商已经有有效位了,补零
                dest[k++] = '0';
        }// if
    }// for
    //::memset(src,0,len);
    //memcpy(src,dest,strlen(dest));
}
char a[100],b[100],c[100],temp[100],ans[100];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(a,'\0',sizeof(a));
        memset(b,'\0',sizeof(b));
        memset(c,'\0',sizeof(c));
        memset(temp,'\0',sizeof(temp));
        memset(ans,'\0',sizeof(ans));
        long long n,m;
        scanf("%lld",&n);
        m=n-1;
        sprintf(a, "%lld", n);
        sprintf(b, "%lld", m);
        multiplication(a,b,c);
        division(c,2,ans);
        printf("%s",ans);
        printf("\n");
    }
}

python:

n=int(input())
i=0
while i < n:
    a=int(input())
    print (int(a*(a-1)//2))
    i=i+1

J:最大值

分析:
正解好像是kmp,但是不会,看了大佬题解我才知道可以用二分蛮过去。
截取字符串0-len,再用非前缀长度为len的字符串与它比较,如果相等就是表示len这个长度可以做到,不相等判断下一个,如此进行二分选择,如果到最后还没有相等的,就是len不行。
代码:

#include "bits/stdc++.h"
using namespace std ;
typedef long long ll;
string s;
ll n,T;
int check(int len){
    string tmp=s.substr(0,len);
    for(int i=1;i+len<=n;i++){
        string q=s.substr(i,len);
        if(q==tmp) return 1;
    }
    return 0;
}
int main(){

    cin>>T;
    while(T--){
        cin>>s;
        n=s.size();
        int l=0,r=n,res;
        while(l<=r){//二分
            int mid=(l+r)>>1;
            if(check(mid)){
                res=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        cout<<res<<endl;
    }
    return 0;
}