SDUT 2021 Summer Individual Contest - 4(for 20)

Odd Palindrome

题意:判断一个字符串的所有子串是不是都是回文奇数串。
思路:枚举所有子串,如果存在偶数回文串就输出no。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
int n,t,a[N];
string st;
bool check(int l,int r)
{
    for(int i=l,j=r;;i++,j--)
    {
        if(i==j||i>j) break;
        if(st[i]!=st[r]) return false;
    }
    return true;
}
int main()
{
    
    cin>>st;
    for(int i=0;i<st.size();i++)
    {
        for(int j=i;j<st.size();j++)
        {
            if(check(i,j))
            {  //cout<<i<<' '<<j<<endl;
               if(i-j+1%2==0)
               {
                   cout<<"Or not."<<endl;
                   return 0;
               }
            }
        }
    }
    cout<<"Odd."<<endl;
}

B - Latin Squares

题意:判断行列不出现重复元素,判断第一行从左到右递增,第一列从上到下递增。
思路:模拟

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
typedef long long LL;
using namespace std;
int g[40][40];
LL n;
int check(int l,int r)
{
  //  cout<<g[l][r]<<endl;
  //  cout<<n<<endl;
    for(int i=1;i<=n;i++)
    {   //cout<<g[1][1]<<"!!!";
        if(g[l][r]==g[l][i]&&i!=r) return 0;
    }
       
    for(int i=1;i<=n;i++)
    {
        if(g[l][r]==g[i][r]&&i!=l) return 0;
    }
       
  //  cout<<l<<"  !  "<<r<<endl;
    return 1;
}
int main()
{
    while(cin>>n)
    {
        for(int i=1;i<=n;i++)
        {
            getchar();
            for(int j=1;j<=n;j++)
            {
                char ss;
                cin>>ss;
                if(ss>='A'&&ss<='Z')
                {
                    g[i][j]=int(ss-'A'+10);
                }
                else
                {
                    g[i][j]=ss-'0';
                }
            }
        }
       /* for(int i=1;i<=n;i++) 
           {
             for(int j=1;j<=n;j++)
           {
               cout<<g[i][j];
           }
           cout<<endl;
               
           }*/
        int flag=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(!check(i,j))
                {
                    flag=0;
                }
            }
        }
        if(flag==0)
        {
            cout<<"No"<<endl;
            continue;
        }
        else
        {
            for(int i=2;i<=n;i++)
            {
                if(g[1][i]!=g[1][i-1]+1)
                {
                    flag=2;
                   // cout<<i<<' '<<'!';
                    break;
                }
            }
            for(int i=2;i<=n;i++)
            {
                if(g[i][1]!=g[i-1][1]+1)
                {
                    //cout<<i<<' '<<'!';
                    flag=2;
                    break;
                }
            }
            if(flag==1)
            {
                cout<<"Reduced"<<endl;
            }
            else if(flag==2)
            {
                cout<<"Not Reduced"<<endl;
            }
        }
    }
    
}


C - Fear Factoring

题意
求1-n中每一个数的所有有因子和,并将这些因子和相加。
例如 1- 3: 1的因子有1, 2的因子有1 + 2 = 3, 3的因子有1+ 3 = 4,最终答案就是 1 + 3 + 4 = 8。
补题来源
除法分块+等差序列求和来解决时间复杂度问题。
n i 为 1 到 n 中 每 一 个 约 数 i 出 现 的 总 次 数 \frac{n}{i} 为1到n中每一个约数i出现的总次数 in1ni
在这里插入图片描述

但是直接枚举花费时间大,这里用等差数列去分块枚举。
左区间每次都是上一个右区间+1。
右区间,比如 10 / 6 = 1 , 10 / 10 = 1 10/6=1,10/10=1 10/6=1,10/10=1,对于约数为1的那些区间,我们用 10 / 1 = 10 10/1=10 10/1=10 可以直接得到右区间端点,具体看博主笔记。

#include <iostream>
#include <cstdio>
#include <algorithm>
/*
    这里我们是用1~b之间额约数和 减去1 ~ a - 1之间的约数和
    所以在求的时候答案可能会爆long long , 这里定义为unsigned long long 
    */
typedef unsigned long long ll;
using namespace std;

ll sum(ll n)
{
    ll ans = 0;
    for(ll left = 1, right; left <= n; left = right + 1 )
    {
        right = n/(n/left);
        // (left + right) * (right - left + 1) / 2 是求的等差数列和
        ans += (left + right) * (right - left + 1) / 2 * (n/left);
    }
    return ans;
}

int main(void)
{
    ll a, b;
    while(cin >> a >> b)
    {
        cout << sum(b) - sum(a - 1) << endl;
    }
    return 0;
}

Halfway

题意:给一个数n,一个项目的完成是 C n 2 C_n{2} Cn2枚举一个从1~n的序列,从前往后,问枚举到合时,项目完成了一般的次数,输出左区间。
思路:直接模拟,先求出总次数,再用等差数列从n递减即可。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL n,m,k,p,x,a[N];
string st;
int main()
{
    cin>>n;
    LL res=0,ans;
    res=n*(n-1);
    res/=2;
    if(res%2==0) ans=res/2;
    else ans=res/2+1;
    for(int i=1;i<=n;i++)
    {
        ans-=n-i;
        if(ans<=0)
        {
            cout<<i<<endl;
            return 0;
        }
    }
}

Unloaded Die

题意:一个六面的筛子得分期望为3.5,每个面出现的几率是六分之一,给定六个面特殊的概率,如果通过修改一个面的面值,达到这个筛子的期望和正常骰子期望一致,而且希望改变的面值尽可能小,求改变面值的绝对值之差。
思路:求最小改变量 △ x △x x,先把当前期望算出来与3.5做个差—— △ y △y y,再算出题目给的最大概率 p p p,最小改变量 △ x = △x= x= △ y p \dfrac{△y}{p} py,贪心点在如果希望改变的面值小,那么就把数值加到出现某一面概率大的一面上即可。

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>

using namespace std;
double s[10];
typedef long long LL;
int main()
{
    double a,b,c,d,e,f;
    double mx=0;
    cin>>s[1]>>s[2]>>s[3]>>s[4]>>s[5]>>s[6];
    double ans=0;
    for(int i=1;i<=6;i++)
    {
        mx=max(mx,s[i]);
        ans+=i*s[i];
    }
    double xx=abs(3.5-ans);
    double y=xx/mx;
    printf("%.3lf\n",y);
    
}

Star Arrangements

模拟,枚举的时候需要注意题目描述的相邻出解,我的做法比较暴力。

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
typedef long long LL;
using namespace std;
double s[10];
LL n;

bool check1(int l,int r)
{
    for(int i=1;;i++)
    {
        if((i+1)*l+(i)*r==n) return true;
        if((i+1)*l+(i)*r>n) return false;
    }
}
bool check2(int l,int r)
{
    for(int i=1;;i++)
    {
        if(i*l+(i)*r==n) return true;
        if(i*l+(i)*r>n) return false;
    }
}
int main()
{
    cin>>n;
    cout<<n<<":"<<endl;
    for(int i=2;i<n;i++)
    {
        if(check1(i,i-1)||check2(i,i-1)) cout<<i<<','<<i-1<<endl;
        if(check2(i,i)||check1(i,i)) cout<<i<<','<<i<<endl;
    }
}

L - Delayed Work

题意:给定k,p,x。每个工人可以工作k天,每天需要交p的罚款,每个人要交x的租金。实际需要过的天数为 k m \dfrac{k}{m} mk,m为租赁的人数,该人数可以为任意值,让你挑选租赁人数,使得花费最小。
思路:假设租赁的人数为 n n n , 花费 c o s t = cost= cost= n ⋅ x + k n ⋅ p n·x+\dfrac{k}{n}·p nx+nkp,由均值不等式可知当 n = n= n= k ⋅ p x \sqrt{\dfrac{k·p}{x}} xkp 时 , 取得最小值 2 x ⋅ k ⋅ p 2\sqrt{x·k·p} 2xkp
在这里插入图片描述

从题的范围可以看出 n = n= n= k ⋅ p x \sqrt{\dfrac{k·p}{x}} xkp ,最坏k和p取max,x取1.此时n=1e5。所以可以暴力枚举前1e5个数据,更新最小值即可。当然因为已知n在此点取到了最小值,也可以仅枚举 n , n − 1 , n + 1 n,n-1,n+1 n,n1,n+1 这三个点求最小值。
在这里插入图片描述

Forbidden Zero

题意:给一个数n,让你求下一个字典序递增且不含0的数。如 9 − − − − 11 9----11 911
思路:从右往左找连续个 9 9 9的个数,然后求个数的十次方和。比如 1199 1199 1199,两个 9 9 9,和就是 1 0 2 + 1 0 1 + 1 0 0 = 12 10^2+10^1+10^0=12 102+101+100=12 , 所以答案就是 1211 1211 1211

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
int n,t,a[N];
string st;

int main()
{
    cin>>n;
    LL m=n,res=0,ans=0;
    LL p=n,ct=0;
    while(p)
    {
        int x=p%10;
        if(x!=9) break;
        p/=10;
        if(x==9) ct++;
    }
    for(int i=ct-1;i>=0;i--)
    {
        ans+=pow(10,i);
    }
     if(n%10==9)
     cout<<n+ans+1;
     else
     cout<<n+1;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值