题目链接

A题

题意
给一个字符串
问字符串里有没有出现子序列"XiaoQiao"和“XiaoHuiHui”
题解
用两个字符串存入,并对给定字符串进行On查询

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    string t="XiaoQiao";
    string s;cin>>s;
    int j=0;
    for(int i=0;i<s.length();i++){
        if(s[i]==t[j])j++;
        if(j==t.length())break;
    }
    if(j<t.length()){cout<<"emm"<<endl;return 0;}
    string tt="XiaoHuiHui";
    j=0;
    for(int i=0;i<s.length();i++){
        if(s[i]==tt[j])j++;
        if(j==tt.length())break;
    }
    if(j<tt.length())cout<<"emm"<<endl;
    else cout<<"Happy"<<endl;
    return 0;
}

B题

题意
在二维平面中给定n个点,每个点有坐标 xi,yi
需要让这n个点连通
第i个点和第j个点建路所需要的花费为
图片说明
问最少需要花费多少
题解
将公式的分离开化简,这里只看

图片说明
由此式子化简可得到
图片说明

所以将每个点的值计算出来,排序后让相邻两条建路是最短的
由于图片说明
可以推出最后的结果应该是图片说明

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f;
vector<ll> a;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        ll x,y;cin>>x>>y;
        a.pb(y*(x-y)*(x-y));
    }
    sort(all(a));
    cout<<*(a.end()-1)-*a.begin()<<endl;
    return 0;
}

C题

题意
件材料 件材料 有两种方法合成装备 件材料件材料可以合成一套装备 件材料件材料可以合成一套装备
问最多能合成多少套装备

题解
官方题解用的是三分
我用的方法是贪心,尽量先用件材料件材料可以合成一套装备,当材料和材料剩余个数是4:1的的时候开始用第二种方法合成装备
设使两个材料之比变成4:1需要用第一种方法合成


化简可以得到
所以可以得到
(其中表示化成4:1需要多少次)


当然可能这个值会被整除,所以要通过四舍五入判断是应该多算一次第一种情况还是多算一次第二种情况,所以式子变为

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;cin>>t;
    while(t--){
        ll x,y;
        cin>>x>>y;
        if(4*y<x){cout<<y<<endl;continue;}
        ll d=(4*y-x+5)/10;
        d=min(x/2,d),d=min(y/3,d);
        ll ans=0;
        ans+=d;
        x-=2*d,y-=3*d;
        cout<<ans+min(x/4,y)<<endl;
    }
    return 0;
}

D题

题意轮流取石子,一共有个石子,先开始取
假设当前的石子有
的时候B获得胜利
的时候将式子分为 两堆,必须取走其中一堆,为满足的最大整数
最后问谁能获得胜利
题解
由于的范围是,所以不能采取暴力的方法计算
需要打表找规律
如果上次连续赢的长度为,可以发现会连续赢
如果上次连续赢的长度为,可以发现会连续赢
所以可以使用的复杂度去找n在谁获胜的区间里

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;cin>>t;
    while(t--){
        ll n;
        cin>>n;
        ll x=1,y=2;
        bool f=1;
        while(x<n){
            if(!f)x+=y,y=2*y+1,f=1;
            else x+=y,y=y*2-1,f=0;
        }
        if(!f)cout<<"XiaoHuiHui"<<endl;
        else cout<<"XiaoQiao"<<endl;
    }
    return 0;
}

E题

题意
一共有堆石子,每堆有个石子,牛牛要把它们搬走
如果一次搬了个石子,会对牛牛产生的负担
牛牛最多搬
牛能每次会将第堆的石子数量变为,所以每次需要重新计算牛牛的最小负担(总共次)
题解
由于数据较小
可以采用的方法,但是由于石子的数量是改变的,可以通过线段树来优化
是在线段树的第个结点,把第组分隔次的最小负担

状态转移方程如下:
先将叶子结点的0到m-n次分割的最小情况计算出来
然后通过转移方程推广到各个非终端结点
最后

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f;

ll dp[410<<2][410];
int n,m;

void update(int p,int l,int r,int x,ll v){
    if(l==r){
        for(int i=0;i<=m-n;i++){
            ll t=v/(i+1);
            ll a=v%(i+1),b=(i+1)-a;
            dp[p][i]=b*t*t+a*(t+1)*(t+1);
        }
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)update(p<<1,l,mid,x,v);
    else update(p<<1|1,mid+1,r,x,v);
    for(int i=0;i<=m-n;i++)
        dp[p][i]=inf*inf;
    for(int i=0;i<=m-n;i++)
        for(int j=0;i+j<=m-n;j++)
            dp[p][i+j]=min(dp[p][i+j],dp[p<<1][i]+dp[p<<1|1][j]);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n>>m;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        update(1,1,n,i,x);
    }
    int q;cin>>q;
    while(q--){
        int x,v;
        cin>>x>>v;
        update(1,1,n,x,v);
        cout<<dp[1][m-n]<<endl;
    }
    return 0;
}