• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
AC_Artist.zig_zag
然而我依然在补题、
博客园    首页    新随笔    联系   管理    订阅  订阅

bzoj 3119 book

题意:给你一个N项数列的首项X,之后的每一项要么比前一项多A,要么少B,N项前缀和为M,构造一个可行的数列。

分析:首先,后一项只和前一项有关,那么对于一项来说+A和-B都是对后面每一项都造成影响的,比如第i个位置选择+A,那么后面N-i+1个位置相对都+A。于是我们设一共加了x个A,y个b,容易得到:

ax+by=M-N*X

x+y=n*(n-1)/2

这样我们可以解得x和y,那么怎么求方案呢?

我们看到x和y是由1..n-1这些数组合而成的。并且我们发现,1..n*(n-1)/2中所有的数都可以用1..n-1中得数组合成,我们观察组合的过程(以10为例),1=1,2=2,3=3...11=10+1,12=10+2...20=10+9+1,21=10+9+2...28=10+9+8+1,29=10+9+8+2...45=10+9+8+7+6+5+4+3+2+1,我们看到这些数的组合规律:从后向前贪心地选取大数,能选则选,到最后一定可以组合成要求的数。

于是我们就可以这样把组成x的数求出来,从而得到每一个位置是+A还是-B了。

贴个代码:

book
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 using namespace std;
 7 long long N,M,n,m,x,y,X,A,B;
 8 bool v[200000];
 9 
10 int main()
11 {
12     scanf("%lld",&N);
13     scanf("%lld%lld%lld%lld",&X,&A,&B,&M);
14     m=M-N*X;
15     n=N*(N-1)/2;
16     x=(m+B*n)/(A+B);
17     y=n-x;
18     int now=N-1;
19     while (x)
20     {
21         if (x-now>=0)
22         {
23             v[now]=1;
24             x-=now;
25         }
26         now--;
27     }
28     printf("%lld",X);
29     for (int i=N-1;i>=1;i--)
30     {
31         if (v[i]) X+=A; else X-=B;
32         printf(" %lld",X);
33     }
34     printf("\n");
35     return 0;
36 }
37     

 

AC without art, no better than WA !
posted @ 2013-04-18 08:13  Zig_zag  阅读(362)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3