题解9.29-10.3

1.MakeitAlternating
如果它已经是交替的序列我们就不用管了,最终的目的是把序列变成交替的序列,那么我们可以把连续相同的数
全部取出来只留下一个,可以分成几段相同的数,最后的结果就是把这些相同的数全部只保留一个,用排列组合C(m,1);
第一个结果很简单,把重复的数加一下即可,后面的答案我们用C(m,1)算出来每个的数量,最后把拿出来的数全排列一下就行。

#include <bits/stdc++.h>

using namespace std;
#define int long long int


int MOD =998244353;

int res[2000001];
//预处理把所有的阶乘算出来
void init()
{
    res[0] = 1;
    for (int i = 1; i <= 200000; i++)
    {
        res[i] = res[i - 1] * i % MOD;
        // cout << res[i] << ' ';
    }
}


int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    init();
    int t;
    cin>>t;
    while(t--){
        string s;
        cin>>s;
        int cs=0;
        int ans=1;
        int q=1;

        char cnt=s[0];
        for (int i =1; i < s.length(); ++i) {
            if(s[i]==cnt)cs++,q++;
            else{
                cnt=s[i];
                if(q!=1)
                ans*=q;
                ans%=MOD;
                q=1;
            }
        }
        if(q!=1){
            ans*=q;
            ans%=MOD;
            q=1;
        }
        if(ans==1) cout<<cs<<' '<<1<<'\n';
        else
        cout<<cs<<" "<<(res[cs]*ans)%MOD<<'\n';
    }
    return 0 ;
}

2. 2.C. Black Circles
两点之间直线最短,如果刚好相切,可以画图证明一下也是可以的,这里注意不要用sqrt精度不行,所以直接用乘积比较

#include <bits/stdc++.h>
using namespace std;
#define int long long
struct node{
    int x;
    int y;
}v[100001];
int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for (int i = 1; i <=n ; ++i) {
            cin>>v[i].x>>v[i].y;

        }
        int tx,ty;
        int ex,ey;
        cin>>tx>>ty;

        cin>>ex>>ey;
        int pd=0;
        int dis=((tx - ex) * (tx - ex) + (ty - ey) * (ty - ey));
        for (int i = 1; i <=n; ++i) {
            int dis1=((v[i].x - ex) * (v[i].x - ex) + (v[i].y - ey) * (v[i].y - ey));
            if(dis1<=dis){
                pd=1;
                break;
            }
        }
        if(pd)cout<<"NO\n";
        else cout<<"YES\n";
 }

}

3.The Strict Teacher (Hard Version))
二分,给出的数是有顺序的,目的是找最接近的左边和右边的数,两边二分即可

#include <bits/stdc++.h>
using  namespace  std;

#define  int long long

int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--){
        int n,m,q;
        cin>>n>>m>>q;
        set<int>st;
        set<int,greater<>>st2;
        st.insert(0);
        st2.insert(0);
        for (int i = 1; i <=m ; ++i) {
              int b;
              cin>>b;
              st.insert(b);
              st2.insert(b);
        }
        while(q--){
            int d;
            cin>>d;
            int f=*st.upper_bound(d);
            int h=*st2.upper_bound(d);
            if(f<=d){
                cout<<n-h<<'\n';
            }else if(h==0){
                cout<<f-1<<'\n';
            }else{
                cout<<(f-h)/2<<'\n';
            }
           // cout<<"f: "<<f<<" h: "<<h<<'\n';

        }
    }
}

4.F.Sakurako'sBo
考察题目逆元的性质,计算除法的时候会改变值,这个时候我们用快速幂逆元写即可

#include <bits/stdc++.h>
using  namespace  std;

#define  int long long


int MOD=1000000007;
int f[1008611];
int pre[1008611];
int qpow(int a,int n)
{
    int res=1;
    while(n){
        if(n&1) res=res*a%MOD;
        n>>=1;
        a=a*a%MOD;
    }
    return res;
}

int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        pre[0]=0;
        for (int i = 1; i <=n ; ++i) {
            cin>>f[i];
            pre[i]=pre[i-1]+f[i];
        }
        int sum=0;
        for (int i = 1; i <n ; ++i) {
            sum+=((f[i]%MOD*((pre[n]-pre[i])%MOD)%MOD))%MOD;
            sum%=MOD;
        }
        int fm=(n*(n-1)/2)%MOD;//这也要记得mod
        cout<<(sum%MOD* qpow(fm,MOD-2))%MOD<<'\n';
    }
}

5.C. Absolute Zero
找规律发现,以最大的数依次除二与数组进行取绝对值,最后会变成1或者是0,我一开始直接拿最大的数操作,但是wa了二,很明显
最大的数有可能进行40次操作不一定够,于是想到数据的范围不超过2的30次方,那么我们把最大的数设置为2的29次方,拿最终经过30或者31次操作必有解

#include <bits/stdc++.h>
using  namespace  std;

#define  int long long


int MOD=1000000007;
int f[1008611];
int qpow(int a,int n)
{
    int res=1;
    while(n){
        if(n&1) res=res*a;
        n>>=1;
        a=a*a;
    }
    return res;
}

int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        int maxx=0;
        int maxd=0;
        int ji=0;
        int ou=0;
        for (int i = 1; i <=n ; ++i) {
            cin>>f[i];
            if(f[i]%2==0)ou=1;
            else ji=1;
            maxd=max(maxd,f[i]);
        }
        int pd=0;

        if(maxd==0){
            cout<<0<<'\n';
            cout<<'\n';
            continue;
        }
        if(ji&&ou)pd=1;
        maxx= qpow(2,29);
        if(pd){
            cout<<-1<<'\n';
        }else{
            int ans=0;
            int res=maxx;
            int d=abs(f[n]-1);
            while(maxx>0){
              //  cout<<maxx<<' ';
                d=abs(d-maxx);
                maxx/=2;
                ans++;
                if(ans>40){
                    pd=1;
                    break;
                }
            }
            if(pd){
                cout<<-1<<'\n';
                continue;
            }if(ans!=0&&d==0)
            cout<<ans+1<<'\n';
            else if(ans!=0&&d==1){
                cout<<ans+2<<'\n';
            }
            else
                cout<<ans<<'\n';
            while(res>0){
                cout<<res<<' ';
                res/=2;
                ans++;

            }
            if(ans!=0)
            cout<<1<<' ';
            if(ans!=0&&d==1)
                cout<<1<<' ';
            cout<<'\n';
        }
    }
}

6.B. Battle Cows
题单上写的二分,我一直往二分方向考虑,想不出来,后面看题解发现根本不是二分的思路,我们如果要比赛赢的
最多,我们必须比前面的都大,这个时候我们跟第一个数交换,如果前面出现比自己的数大,那么我们就跟从第一个
开始比自己大的数交换,然后比较这两个数谁大就行

#include <bits/stdc++.h>
using namespace std;

int a[1008611];
void solve()
{
    int n,k,i; cin>>n>>k;
    for(i=1;i<=n;i++) cin>>a[i];
    swap(a[k],a[1]);
    int ans1=0;  //与第一个人交换的方案的胜场数
    for(i=2;i<=n;i++)
    {
        if(a[i]>a[1]) break;
        else ans1++;
    }
    swap(a[k],a[1]); //swap回来进行下一个方案的求解

    int flag=n+1,ans2=0; //flag为第一个比k大的人的下标
    for(i=1;i<=n;i++)
        if(a[i]>a[k])
        {
            flag=i;
            break;
        }
    if(flag<k)
    {
        swap(a[k],a[flag]);
        if(flag>1) ans2++;//特判当前k是不是在开头,否则会赢前面的人一场
        for(i=flag+1;i<=n;i++)
        {
            if(a[i]>a[flag]) break;
            else ans2++;
        }
    }
    cout<<max(ans1,ans2)<<"\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin>>t;
    while (t--){
        solve();
    }
}

7.1.E. Secret Box
不难,但是思路错了,我的想法是它要凑出x,y,z的数量,并且x,y,z的点必须是相联的,
然后我去计算点数的时候也出错了,就一直想不通,其实大体思路没错,但是没有想清楚,每个点
从1开始向后移动就是连续的了,我们只需要枚举x,y,用k/x*y,去找c即可,最主要的原因还是没有分析
清楚,找不出计算的规律

#include <iostream>
using namespace std;
using ll = long long;

int main(){
	int t; cin >> t;
	while(t--){
		ll x, y, z, k; cin >> x >> y >> z >> k;
		ll ans = 0;
		for(int a = 1; a <= x; a++){
			for(int b = 1; b <= y; b++){
				if(k % (a * b)) continue;
				ll c = k / (a * b);
				if(c > z) continue;
				ll ways = (ll)(x - a + 1) * (y - b + 1) * (z - c + 1);
				ans = max(ans, ways);
			}
		}
		cout << ans << "\n";
	}
}
posted @ 2024-10-03 16:40  冬天的睡袋  阅读(3)  评论(0编辑  收藏  举报