【Wannafly挑战赛5】 A 【思维枚举】B C【排列组合 公式】

A 珂朵莉与宇宙
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 65536K,其他语言131072K
64bit IO Format: %lld
题目描述
星神是来自宇宙的
所以珂朵莉也是吧
所以我就出了个题
给你一个长为n的序列a,有n*(n+1)/2个子区间,问这些子区间里面和为完全平方数的子区间个数
输入描述:
第一行一个数n
第二行n个数表示序列a
输出描述:
输出一个数表示答案
示例1
输入

6
0 1 0 9 1 0
输出

11
备注:
1 <= n <= 100000
0 <= ai <= 10

分析 : 墨迹半天终于墨迹出来 ,TAT 。
第一眼看上去,没有什么好的思路,之后想了好多种方法来解决,各种暴力,DP,貌似都是不行的, 然后看了数据 a[i] 的范围才10,觉得这个应该是个突破口,但是之前想的都没有用到这个关键条件,肯定是不对的,然后再看n的范围,1e5,猜复杂度吧, 应该是o(n*sqrt(n)) . 但是对于sqrt(n)时间复杂度的算法貌似没有几个吧,而且都和这个毫无关系。思路又断了。对于这种区间和问题,肯定要有前缀表 , 写出来数学表达式子,看看有没有什么好的思路吧, ==》 ( sum[ri]-sum[le-1] ) = c * c 。a - b = c * c , a = c * c + b 突然有了感觉,我们可以先枚举b,然后再枚举c,c最大枚举到sqrt( n * a[i] ) , 然后就发现有了sqrt的复杂度, 并且a[i]的大小也用上了,a[i]再大一个0这个方法也就用不上了, 正好和猜测的差不多,应该就是这个思路了。
思路: 有了前缀和之后,我们o(n)的枚举 sum[le-1] , 然后再sqrt的枚举c ,然后ans+= 当前位置之后 a 的个数 。

时间复杂度 o(n * sqrt(n*a[i]))
代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 100000+2;
const int inf = 1e6+11; // n * 10

int sum[MAXN+11]; // 前缀和
 int cnt[inf+11]; // 前缀和 的个数。
int ge[inf+11];
int main(){
    int n;
    while(~scanf("%d",&n)){
        int a; sum[0]=0;
        memset(cnt,0,sizeof(cnt));
        memset(ge,0,sizeof(ge));
        cnt[0]++;// 注意0 也要算
        for(int i=1;i<=n;i++){
            scanf("%d",&a);
            sum[i]=sum[i-1]+a;  cnt[sum[i]]++;
        }
     //   for(int i=1;i<=n;i++) printf("%d ",sum[i]);puts("");
        LL ans=0;
        for(int b=0;b<n;b++){ 
            ge[sum[b]]++; // 记录截止到当前位置,有几个sum[b]
            for(int c=0;c*c<=inf;c++){
                a=sum[b]+c*c ;
                if(a>sum[n]) break; // 之后肯定没有意义
                ans+=cnt[a]-ge[a]; // 所有的a的个数 - 包括自身之前的a的个数,因为a的位置一定是大于b的位置
            }
        }
        printf("%lld\n",ans);
    }
return 0;
}

B 可编程拖拉机比赛
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 65536K,其他语言131072K
64bit IO Format: %lld
题目描述
“这个比赛,归根结底就是控制一个虚拟的小拖拉机跑完整个赛道。一般一场比赛会有 9 个到 13 个赛道,最后看能跑完多少个赛道。”
通常在一场可编程拖拉机比赛中,分别会有实际参赛队伍数 10%、20%、30% 向下取整的队伍获得金、银、铜牌,其余队伍获得荣誉提名,俗称“铁牌”。
但是主办方往往会多准备一些奖牌,那么在发奖牌的时候会按照比例向上取整发出的奖牌以减少浪费,就会有一些原本获得银牌的队伍获得了金牌。
现在给出一个赛区的规模,也就是这个赛区的实际参赛队伍数,小 Q 同学想知道有多少队伍的奖牌会由银变金、由铜变银、由铁变铜。

输入描述:
输入只有一行,包含一个整数 n (10 <= n <= 1000),表示实际参赛队伍数。
输出描述:
输出一行,包含三个由空格分隔的整数,分别表示奖牌会由银变金、由铜变银、由铁变铜的队伍数。
示例1
输入

115
输出

1 1 2
说明

按照下取整规则只发 11 块金牌的话,第 12 名原本是银牌,但是按照上取整规则发 12 块金牌,第 12 名是金牌,就由银变金了。

分析 :水题 。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100 ;


int main(){
    int n;
    while(cin>>n){
        int a=floor(n*0.1); int aa=ceil(n*0.1);
        int b=floor(n*0.2); int bb=ceil(n*0.2);
        int c=floor(n*0.3); int cc=ceil(n*0.3);
        int x=a,xx=aa;  //  不同取整前后,金银铜最后一个人的位置 
        int y=x+b,yy=xx+bb;
        int z=y+c,zz=yy+cc;

        printf("%d %d %d\n",xx-x,yy-y,zz-z);
    }
return 0;
}

C 子序列
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给定一个小写字母字符串T
求有多少长度为m的小写字母字符串S满足,T是S的一个子序列(不需要连续)
输入描述:
第一行一个字符串T
第二行一个正整数m
输出描述:
输出答案对109+7取模的值
示例1
输入

a
2
输出

51
说明

长度为2的里面有a的串有51种
备注:
1<=|T|,m<=105

公式 :
1 从n个不同的物体中可重复的抽取m个不考虑顺序的种类数为 C(n+m-1,m) .
2 从n个不同的物体中可重复的抽取m个进行排列(考虑顺序)的种类数为 n^m == ∑(i=0 - i=m) C(m,i)*(n-1)^(m-i) 。
本题 相当于从 i=T.size() - i=m .

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 100000+2;
const int inf = 1e6+11;
const int mod = 1e9+7 ;

int fac[MAXN+1];
void init(){
    fac[0]=1;
    for(LL i=1;i<=MAXN;i++) 
         fac[i]=fac[i-1]*i%mod;
}
LL qpow(LL a,LL b,LL c){
    LL s=1,base=a%c;
    while(b){
        if(b&1) s=s*base%c;
        base=base*base%c;
        b>>=1;
    }
    return s;
}
LL inv(int a){ return  qpow(a,mod-2,mod); }
LL C(int n,int m){
    return fac[n]*inv((LL)fac[n-m]*fac[m]%mod)%mod;
}
int main(){
    init();
    string T;int m;
    while(cin>>T>>m){
        int n=26;
        if(m<T.size()) { puts("0"); continue; }
        LL ans=0;
        for(int i=T.size();i<=m;i++) {
            ans+=C(m,i)*qpow(n-1,m-i,mod)%mod;
            ans%=mod;
        }
        cout<<ans<<endl;
    }
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值