A

solution:

找规律题
n = 0 , a = 1 , b = 0
n = 1 , a = 2 , b = 1
n = 2 , a = 3 , b = 2
n = 4 , a = 5 , b = 3
n = 5 , a = 8 , b = 5
递推式: b[i] = a[i-1],a[i] = b[i] + b[i-1];

std:

#include <bits/stdc++.h>
using namespace std;
#define ll  long long
ll a[100],b[100];
void solve(){
    a[0] = 1,b[0] = 0;
    a[1] = 2,b[1] = 1;
    for(int i=2;i<=90;i++){
        b[i] = a[i-1];
        a[i] = b[i] + b[i-1];
    }
    return ;
}
int main()
{
    solve();
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        cout<<a[n] + b[n]<<endl;
    }
    return 0;
}

B

solution:

这题赛后又一次重判了,大家记得再交一发,解法就是stack模拟进栈出栈过程

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
stack<char> sta;
int main()
{
    string s;
    cin>>s;
    if(s.length() == 0){
        cout<<"Yes"<<endl;
        return 0;
    }
    int l = s.length();
    for(int i=0;i<l;i++){
        if(sta.empty()){
            sta.push(s[i]);
        }else{
            int flag = 0;
            char c = sta.top();
            if(c == '[' && s[i] == ']'){
                sta.pop();
            }
            else if(c == '(' && s[i] == ')'){
                sta.pop();
            }
            else if(c == '{' && s[i] == '}'){
                sta.pop();
            }
            else{
                sta.push(s[i]);
            }
        }
    }
    if(sta.size() == 0){
        printf("Yes\n");
    }else{
        printf("No\n");
    }
    return 0;
}

C

solution:

这题做法很多,尺举法,指针,我是记录每个不为0且长度大于等于k的区间,枚举每个区间,类似尺举,一定要记得乘法逆元,忘逆元wa了一发0.0
乘法逆元:a/b mod c = pow_mod(a,c) * pow_mod(b , c-2) %c;

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200005;
const ll mod = 998244353;
ll pow_mod(ll a,ll b)
{
    ll ans = 1;
    while(b){
        if(b&1)
           ans = ans*a%mod;
        a = a*a%mod;
        b>>=1;
    }
    return ans;
}
ll a[maxn];
struct node{
    int l ,r;
};
node b[maxn];
int main()
{
    int n,k;
    scanf("%d %d",&n,&k);
    int l = 0,r = 0,cnt = 0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        if(a[i] == 0){
            int len = i-l-1;
            if(len >= k){
                b[++cnt].l = l+1;
                b[cnt].r = i-1;
            }
            l = i;
        }
    }
    if(n-l >= k){
        b[++cnt].l = l+1;
        b[cnt].r = n;
    }
    ll ans = 0;
    for(int i=1;i<=cnt;i++)
    {
        int l = b[i].l;
        int r = b[i].r;
        ll cnt = 1;
        for(int j=l;j<=l+k-1;j++){
            cnt *= a[j];
            cnt %= mod;
        }
        ans = max(ans , cnt );
        for(int j=l+k;j<=r;j++)
        {
            cnt = cnt%mod*(pow_mod(a[j-k] , mod-2)%mod)%mod;
            cnt *= a[j];
            cnt %= mod;
            ans = max(ans , cnt);
        }
    }
    cout<<ans<<endl;
    return 0;
}

D

solution:

异或前缀和
设pre数组是异或前缀和,如果[l,r]是符合的,那么肯定有pre[l-1]^pre[r] = 0,只需要在输入的时候用一个map记录一下异或和

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200005;
ll n,a[maxn],ans = 0,cnt = 0;
map<ll ,int> mp;
int main()
{
    int n;
    mp[0] = 1;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%lld",&a[i]);
        cnt ^= a[i];
        ans += mp[cnt];
        mp[cnt] += 1;
    }
    cout<<ans<<endl;
    return 0;
}

E

solution:

贪心模拟
贪心模拟,先记录加号的个数k,可以想象将所有的数字从9-1往k+1个数组里加,这样保证小号在前,大的在最后面,最后累加进位,模拟字符串相加即可

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 500005;
char s[maxn];
int a[11],ans[maxn];
int main()
{
    scanf("%s",s+1);
    int l = strlen(s+1),cnt = 1;
    for(int i=1;i<=l;i++){
        if(s[i] >= '1' && s[i] <= '9'){
            a[s[i]-'0']++;
        }else{
            cnt++;
        }
    }
    int pos = 0,k = 0,flag = 0;
    for(int i=10;i>=1;i--){
        while(a[i]){
            ans[k] += i;
            a[i]--;
            pos = (pos + 1)%cnt;
            if(pos == 0){
                k++;
            }
        }
    }
    for(int i=0;i<maxn;i++){
        ans[i+1] += ans[i]/10;
        ans[i]%=10;
    }
    for(int i=maxn;i>=0;i--){
        if(flag || ans[i]){
            printf("%d",ans[i]);
            flag = 1;
        }
    }


    return 0;
}

F

solution:

听着是个树上博弈,其实是个找规律题
首先这是一颗树,任意两点间的距离固定。我们考虑两个人如何才能获胜,肯定是往对方的方向走,让对方无路可走,你可以这样理解,牛牛想获胜,往牛妹的方向走,如果牛牛走道牛妹的跟前,牛妹无法向牛牛的方向移动,哪只能往叶子节点的方向移动了吧,那牛牛就跟在牛妹后面,最后肯定是牛牛堵住了牛妹,相反的就是牛妹走到了牛牛跟前,牛牛无路可走。。。
如果相离的距离为偶数,牛牛必胜(牛牛先手走,距离为2,牛牛走一步到达必胜局面),相离的距离为奇数,牛妹必胜(情况相反)。所以本题就是让你找树上距离为偶数的不同点的个数,

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int a[1000005];
int b[3];
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int main()
{
    int n,x;
    n = read();
    a[1] = 0;
    b[1] = 1ll*1;
    for(int i=2;i<=n;i++){
        x = read();
        a[i] = a[x] + 1;
        if(a[i]%2){
            b[0]++;
        }else{
            b[1]++;
        }
    }
    printf("%lld\n",1ll*b[0]*(b[0]-1) + 1ll*b[1]*(b[1]-1));
    return 0;
}

G

solution:

二分期末分数所占的比例,对于每一种比例x,判断其是否可行。
判断可行的方法是,求优秀人数的期望。根据x可以求出来平时成绩所占的比例,如果平时成绩×(1.0 - x)大于等于90,这个人一定是优sum = sum + 1,如果不满足这个条件,就求一下离90差多少分,根据差值和占比x求出原来期末成绩,只要成绩比这个大或者等于,并且在90之间都可行,所以成绩的区间就是(90 - s),根据这个区间在0到90所占的比例就求出来了这个人优秀的概率p,sum += p,最后sum的和就是优秀人数的期望值,判断期望值和n/10的大小,然后改变二分上下限

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    int x,n,sum = 0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>x;
        sum += x;
    }
    double ans = sum - 90*n;
    printf("%.2lf",(ans/(9*n+ans)*100));
    printf("%\n");
    return 0;
}

H,I,J

solution:no solution 不会。。