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

被折叠的 条评论
为什么被折叠?



