群赛 round#8 解题报告一 (swop,ranwen,easy)

本文提供了群赛Round#8的三道题目解答,包括交换书籍的最大价值获取策略、清洁工清理垃圾的最短时间计算及数字整除性质计数问题。采用枚举、动态规划等算法。

群赛 round#8 解题报告一

赛制: OI 难度: noip

T1 交换!交换!(swop)

【问题描述】
ljm喜欢交换物品,他觉得这样可以与更多人分享好的事物。
有一天,lzx给了ljm n本书,这n本书的有益程度分别是a[i],排成一排。然后lzx告诉他:我可以给你k次机会,你最多可以交换其中k对书的位置,然后在现在的排列中拿走其中连续的一段。
ljm是一个正能量的人,他想使得自己拿走的这一段书有益程度加起来尽量大,所以他决定写一个程序来计算。
【输入格式】
第一行n,k。
第二行n个数字,分别是a[i]。(-1000<=a[i]<=1000)
【输出格式】
一个数字,表示ljm最终拿走的这段书有益程度之和。
【输入样例】
10 2
10 -1 2 2 2 2 2 2 -1 10
【输出样例】
32
【数据范围与约定】
对于100%的数据,n<=200,k<=10。
这个题比较简单,就是枚举取到的区间,然后找出区间内前k小的,与区间外前k大的交换,把此时区间内的值加起来,更新ans即可。复杂度为O(n^3)。
代码如下:

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<limits.h>
#define ll long long
using namespace std;
int k,n,a[300],dp[300][300][15],ans=INT_MIN;
void solve(int l,int r)
{
    int sum=0;
    for(int i=l;i<=r;i++) sum+=a[i];
    ans=max(sum,ans);
    priority_queue<int> qx;
    priority_queue<int> qd;
    for(int i=l;i<=r;i++) qx.push(-a[i]);
    for(int i=1;i<l;i++) qd.push(a[i]);
    for(int i=r+1;i<=n;i++) qd.push(a[i]);
    for(int i=1;i<=k;i++)
    {
        if(qx.size()==0 || qd.size()==0) break;
        sum+=qx.top()+qd.top();
        qx.pop();qd.pop();
        ans=max(ans,sum);
    }
}
int main()
{
    freopen("swop.in","r",stdin);
    freopen("swop.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    for(int j=i;j<=n;j++) solve(i,j);
    printf("%d\n",ans);
 }

T2 冉文的烦恼(ranwen)

【问题描述】
冉文是个粗心的人,经常不小心把垃圾丢到地上。实在没办法,只好派了m个学生,去捡冉文走过路上的垃圾。
假设冉文走过的路线是一条直线,每个位置分别是1..n,每个位置上垃圾的个数是ai。所有学生起始位置都在0,每秒钟,他们有两种选择:
1.向右走一步。
2.捡起一个地上的垃圾。
现在我们的问题是:要捡起冉文的所有垃圾,最少需要多少秒?
【输入格式】
第一行输入两个正整数n,m,如题目所述。
第二行输入n个非负整数ai,代表每个位置的垃圾个数。ai<=10^9
【输出格式】
一个数字,表示最少的时间。
【输入样例】
3 2
1 0 2
【输出样例】
5
解释:第一个学生走到3,然后捡2个垃圾,共花费时间5,第二个学生走到1,捡1个垃圾,共花费时间2。
【数据范围与约定】
对于30%的数据,m=1。
对于另30%的数据,m=2,垃圾总个数<=21。
对于100%的数据,n,m<=100000
这个题前30%可以直接模拟,另30%用2^21表示2人分别捡的垃圾再模拟。对于100%的数据,二分时间,推出所有学生能走到的最远距离,倒回来捡垃圾,看能否在二分的时间内完成即可。注意各种数字不要开的太小,会WA。
代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define ll long long
using namespace std;
ll n,m,a[100005];
bool can(ll lim)
{
    ll now=lim,cnt=1,k=0;
    for(ll i=1;i<=n;i++)
    {
        now--;
        if(now>=a[i]) now-=a[i];
        else
        {
            k=a[i]-now;
            now=0;
        }
        if(i==n&&k<=0) break;
        if(now==0)
        {
            cnt++;
            now=lim-i-k;
        }
        while(now<0)
        {
            cnt++;
            now+=lim-i;
            if(lim-i<=0) return 0;
        }
        k=0;
    }
    if(cnt<=m) return 1;
    return 0;
}
int main()
{
    freopen("ranwen.in","r",stdin);
    freopen("ranwen.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(ll i=n;i>=1;i--)
    {
        if(a[i]==0) n--;
        else break;
    }
    ll l=0,r=1e14*n;
    while(l<r-1)
    {
        ll mid=(l+r)/2;
        if(can(mid)==1) r=mid;
        else l=mid;
    }
    cout<<r<<endl; 
 } 

T3 送分题(easy)

【问题描述】
每个人都会枚举,所以给大家一个送分题。
区间[L,R]内有多少个数字K满足:
K各个非0位都能被K整除?
例如,250的非0位是2,5,250/2=125,250/5=50。
【输入格式】
一行,两个正整数L,R。
【输出格式】
一个数字,表示答案的个数。
【输入样例】
12 15
【输出样例】
2
【数据范围与约定】
对于30%的数据,L,R<=10^5。
对于60%的数据,L,R<=9*10^9。
对于100%的数据,L,R<=10^18。
并不能听信题面……
此题30分做法确实是枚举,60分做法在30分基础上分段打表。对于满分做法,从题面上可以很容易的看出这是一道数位DP。基本思路是用:dp[len][mod][lcm]表示len的长度中,此数为mod,各数位的最小公倍数为lcm的数的个数来进行搜索。但需要进行内存优化:
第二维大小可以从1e18降到2520,方法是%2520.现在的dp数组的内存是18*2520*2520,还是很大。然后再考虑:可以发现某一个数的各个数位的数的最小公倍数最大是2520,而且只能是2520的公约数。而2520的公约数有不超过50个。所以第三维只要用[50]的空间,方法是离散化。‘
代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define ll long long
using namespace std;
ll dp[25][2525][50],x,y;
int shu[25],hash[2525];
int _lcm(int a,int b)
{
   return a*b/__gcd(a,b);
}
ll dfs(int pos,int mod,int lcm,bool lim)
{
   ll ans=0;
   if(pos<=0) return mod%lcm==0;
   if(!lim && dp[pos][mod][hash[lcm]]!=-1) return dp[pos][mod][hash[lcm]];
   int end=0;
   if(lim) end=shu[pos];
   else end=9;
   for(int i=0;i<=end;i++)
   {
      ans+=dfs(pos-1,(mod*10+i)%2520,i?_lcm(lcm,i):lcm,lim&(i==end));
   }
   if(!lim) dp[pos][mod][hash[lcm]]=ans;
   return ans;
}

ll calc(ll a)
{
   if(a<0) return 0;
   int len=0;
   while(a>0)
   {
      shu[++len]=a%10;
      a/=10;
   }
   ll ans=dfs(len,0,1,1);
   return ans;
}
int main()
{
   freopen("easy.in","r",stdin);
   freopen("easy.out","w",stdout);
   memset(dp,-1,sizeof(dp));
   int id=0;
   for(int i=1;i*i<=2520;i++)
   {
      if(2520%i==0)
      {
         hash[i]=id++;
         if(i*i!=2520) hash[2520/i]=id++;
      }
   }
   scanf("%lld%lld",&x,&y); 
   printf("%lld\n",calc(y)-calc(x-1));
}
根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值