0%

前言

听说最早的题目原型是CF13C
下面按这题来讲,其实就是换成了不降。

朴素DP

定义$f_i(X)$ 为前$i$个数变为不降序列且$a_i\le X$的最小步数。
显然有
$f_1(X) = min_{Y\le X}{|a_1-Y|}$
$f_i(X) = min_{Y\le X}{f_{i-1}(Y)+|a_i-Y|}$

离散的DP

可以令${b_i}$为${a_i}$的一个有序copy,复杂度$O(n^2)$。
详情请阅 CF13C Tutorial

单调性优化

$f_i(X) = min_{Y\le X}{f_{i-1}(Y)+|a_i-Y|}=min(f_i(X-1),f_{i-1}(X)+|a_i-X|)$
由绝对值和最小值的性质,$f_i$对于$X$是一个单减的非负函数,并最后保持一个非负值。
考虑其“斜率函数” $g_i(X)=f_i(X+1)-f_i(X)$,则$g_i(X)$单增(不会证)。
$g_i(X)$的值域为有限个小于等于0的整数,我们将值域中每个数对应的最小的$x$写为一个序列(即“变化点”),即序列的最后一个数为使得$g_i(x)=0$的最小的$x$,……

突然发现我还是不会证,,那就没必要了,,大家还是看资料吧。。

参考资料

阅读全文 »

Tips

因为题目实在太多了,代码就不贴在博客里了。。。想看代码的童鞋可以去github上看看。
题目似乎看不了了,我只能凭感觉复述一下题意了。。。

Before

这个比赛有一个资格赛,但是跟蓝桥杯决赛冲突了所以不能参加,没想到老师帮我们申请了参赛资格,意外之喜。
热身刚结束实验室就断电了。。然后吃完饭背着电脑去了没空调的教室。。。

WarmUp

B题就不说了,反正一眼。A题首先肯定要把质数都筛出来,本来想在质数表里直接做的,但是发现写不出来。。。主要是因为对于 $a\leq x\leq b-m+1$ 都要成立,这个放到质数表里细节太多。。。所以想还不如直接交个很好写的二分答案,结果一发过了。。。很无语,要不是怕复杂度不太对这个也是看一眼就能写 = = 。。。C题比较难懂,它定义的线段能组成方形实际上跟线段本身的长度没有关系,读了好久才读懂,反正不会做也无所谓了 =。=

A

题意:D、E、E、S、T 做全排列并且按字典序排序,输出第$n$个$(n\leq 60)$。
题解:用next_permutation打个表就行啦 虽然CE了两次

B

题意:给出一个 $n\times n$ 四连通的字符地图$(n\leq 50)$,只包含’*‘,’#‘两种字符,从’*‘到’#‘要消耗1点能量,从’#'到其他也要消耗1点能量。问从$(1,1)$到$(n,n)$至少要消耗多少能量。
题解:每个字符与相邻的字符建图,做一次单源最短路。可以用dijkstra+队列优化,时间复杂度$O(2n^2logn+4n^2)$。

阅读全文 »

三月份以后就一直没有发过博客蓝桥杯那两篇也是因为跟别人承诺过因为蓝桥杯省赛基本上都是水题实在是没啥好写的压轴题做了也没地方能交毫无意义。比完蓝桥杯省赛以后又开始学dp和流做的都是sb题和old题也没啥好写的。五月份每个周末都有比赛:先是江苏省赛又是买的题还跟湘潭赛一样真tm难还好没有完全按照去年的模式准备这场主要的遗憾是有一个写起来很短的前缀和的题目没想到,再是陕西邀请赛这场主要的遗憾是有一个sb题写得太慢了另外一个矩形枚举倒是没开错但是想法也不对,最后是蓝桥杯决赛每次都很无语填空题和大题的跨度实在太大了权当是旅游。
其实蓝桥杯决赛前后已经没做题了一直在做软件杯的网站和各种杂事昨天打了金马五校赛和计蒜客一下子做了这么多题而且感觉还不错于是决定今天还是要把解题报告发一下然后一打开博客发现都这么久没更新了又有这么多次比赛没总结所以又临时加了这一篇。从它仅有的标点判断我觉得能看完的人一定都是真爱23333333

阅读全文 »

唉。。。写篇blog纪念一下浪费了我半个上午时间的问题。。。
写的是这么一个代码:

1
while pre.time != now.time:

pre是从数据库取出来的一条记录,now是我准备插入的一条记录,.timedatetimeField,对应程序里就是一个datetime对象。
结果这个条件怎么都是真的,也就是说pre.timenow.time总是不相等,我输出了一下发现pre.time是utc时间而且最后会带一个+00:00
想到以前看到过的warning其实很好查到。now.time是一个 naive time,而pre.time是一个 aware time,其实就是带不带时区的问题,所以只要让now.time带上时区变成 aware time 就可以了。
然后就去查怎么变,其实第一个查到的就是对的。。。只是代码给的不全导致我产生了误解。。。查到的代码是:

1
aware_time = naive_time.replace(tzinfo=utc)

写进去就显示 unresolved reference 我就觉得它很不靠谱,接着就查到了其他的问题。。。

  1. 比如一个字符串Sun, 28 Aug 2016 11:42:00 +0200其实最后是带着时区的,那么怎么转换成 aware time呢?方案是:
1
2
from datetime import datetime
date_published = datetime.strptime(date_published, "%a, %d %b %Y %H:%M:%S %z")

看起来很棒棒啊!我就想直接给我的字符串也带上时区:time_str += u' +0800',然后再用这个方法岂不是美滋滋?
结果就是一直 not match 。%z %Z +08:00 utc+8 都试了,甚至还查到了CCT啥的,还是不行。。。SO要给我精神损失费啊TAT
2. attribute ‘tzinfo’ of ‘datetime.datetime’ objects is not writable
题主写的是 book.creationTime.tzinfo = EST
答主说改成 book.creationTime = book.creationTime.replace(tzinfo=EST)
我一想这人有点傻啊,但是他能用EST我也能用吧,反正加上了时区一切好说,大不了我再加加减减调整一下。。。大概是aware_time = naive_time.replace(tzinfo=EST) 很显然还是不行TAT

最终解决方案:看这些查到的代码我一直以为既然有tzinfo这个类,应该就会有实现好的类,然而问这些的人可能都import pytz了。。。所以如果不想加上pytz实际上最佳的方案就是实现一个tzinfo的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from datetime import datetime, timedelta, tzinfo

ZERO_TIME_DELTA = timedelta(0)
LOCAL_TIME_DELTA = timedelta(hours=8) # 本地时区偏差


class LocalTimezone(tzinfo):
"""实现北京时间的类"""

def utcoffset(self, dt):
return LOCAL_TIME_DELTA

def dst(self, dt):
return ZERO_TIME_DELTA

def tzname(self, dt):
return '+08:00'


forma = "%Y-%m-%d %H:%M"
now.time = datetime.strptime(time_str, forma).replace(tzinfo=LocalTimezone())
阅读全文 »

1. 方程整数解

方程: a^2 + b^2 + c^2 = 1000
这个方程有整数解吗?有:a,b,c=6,8,30 就是一组解。
你能算出另一组合适的解吗?
请填写该解中最小的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <bits/stdc++.h>
using namespace std;

int main()
{
for (int i=1;i<=33;i++) {
for (int j=i;j<=33;j++) {
for (int k=j;k<=33;k++) {
if (i*i+j*j+k*k==1000) {
printf("%d %d %d\n",i,j,k);
}
}
}
}
return 0;
}

答案:10

2. 星系炸弹

在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。
每个炸弹都可以设定多少天之后爆炸。
比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸。
有一个贝塔炸弹,2014年11月9日放置,定时为1000天,请你计算它爆炸的准确日期。
请填写该日期,格式为 yyyy-mm-dd
即4位年份2位月份2位日期。比如:
2015-02-19
请严格按照格式书写。不能出现其它文字或符号。

想一下,我们用的可是一台电脑!写这个程序的话实在是太费时间了。

Step1.

复制“2014年11月9日”,粘贴到excel,并把单元格格式改成日期

阅读全文 »

9. 垒骰子

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
经过长期观察,atm发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。
atm想计算一下有多少种不同的可能的垒骰子方式。
两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
由于方案数可能过多,请输出模 10^9 + 7 的结果。
不要小看了 atm 的骰子数量哦~

「输入格式」
第一行两个整数 n m
n表示骰子数目
接下来 m 行,每行两个整数 a b ,表示 a 和 b 数字不能紧贴在一起。

「输出格式」
一行一个数,表示答案模 10^9 + 7 的结果。

「样例输入」
2 1
1 2

「样例输出」
544

「数据范围」
对于 30% 的数据:n <= 5
对于 60% 的数据:n <= 100
对于 100% 的数据:0 < n <= 10^9, m <= 36

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。

这道题首先要会递推的做法。
很自然的,我们可以用$f[i][j]$表示垒了$i$个骰子,并且最上面的骰子$j$面朝上。
那么递推式就是$$f[i][j]=\sum_{k=1}^{6} f[i-1][k]\quad coop[op[j]][k]$$
其中$op[j]$表示$j$的背面,$coop[op[j]][k]$就表示$j$的背面是可以跟$k$放在一起的。
这样每次没有讨论侧面的朝向,所以最后乘以$4^n$。
如果想要实现的好的话还要使用滚动数组 滚动数组资料

放一个搜到的代码吧。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
using namespace std;

// ...冲突记录: Compact[i][j]=false代表点数为i的面与点数为j的面存在冲突
bool Compact[7][7];

// ...Parner[i]=j代表 点数为i的面 的对立面点数为j
const int Parner[7]={ 0,4,5,6,1,2,3 };
const long long MOD = 1000000007;

int main(int argc, char** argv)
{
long long N; // 骰子高度
int M; // 冲突组数
int s1,s2;
cin >> N >> M;
for( int i = 0; i < 7; ++i)
for( int j = 0; j < 7;++j)
Compact[i][j]=true;

for( int i = 0; i < M; ++i ) {
cin >> s1 >> s2;
// ...点数为s1的面与点数为s2的面存在冲突
Compact[s1][s2] = Compact[s2][s1] = false;
}
long long dp[2][7]; // 滚动数组
long long C = 4;
int e = 0; // 滚动标志
for( int i = 1; i < 7; ++i )
dp[e][i] = 1;

// dp[i][j]代表高度为i的,顶面点数为j的叠骰子方案数
// 在这里忽略每个骰子可以四面转向的情况, 把该情况留到最后乘上去就可以了
int j,k;
for( long long i = 2; i <= N; ++i ){
e = 1-e; // ...滚动处理
C = (C*4)%MOD;
for( j = 1; j < 7; ++j ){
dp[e][j] = 0;
for( k = 1; k < 7; ++k)
if( Compact[ Parner[j] ][k] )
dp[e][j] += dp[1-e][k];
dp[e][j]%=MOD;
}

}
int sum=0;
for( int i = 1; i < 7; ++i)
sum = (sum+dp[e][i])%MOD;
sum = (sum*C)%MOD;
cout << sum;
return 0;
}

核心代码的复杂度$T(n)=36n$,就算给了2s肯定也是不能全通过的,我们需要一个更快的方法。
分析可以发现其实每一步递推对应的关系都是一样的,就是最开始给出的那些关系。
所以我们可以用矩阵来进行递推,再使用快速幂即可 矩阵递推资料

代码用了模板技术,大家凭感觉吧。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int MO=1e9+7;
const int opps[]={0,4,5,6,1,2,3};

struct Mat {
int r,c;
ll el[10][10];
Mat() {}
Mat(ll x) {
r=c=6;
memset(el,0,sizeof(el));
for (int i=1;i<=r;i++) {
el[i][i]=x;
}
}
Mat(int _r,int _c,ll x) {
r=_r;c=_c;
for (int i=1;i<=r;i++) {
for (int j=1;j<=c;j++) {
el[i][j]=x;
}
}
}
Mat operator *(const Mat &b) {
Mat res(r,b.c,0);
for (int i=1;i<=r;i++) {
for (int j=1;j<=b.c;j++) {
for (int k=1;k<=c;k++) {
res.el[i][j]+=el[i][k]*b.el[k][j];
}
}
}
return res;
}
Mat operator %(const int Mo) {
for (int i=1;i<=r;i++) {
for (int j=1;j<=c;j++) {
el[i][j]=el[i][j]%Mo;
}
}
return (*this);
}
void print() {
for (int i=1;i<=r;i++) {
for (int j=1;j<=c;j++) {
printf("%I64d ",el[i][j]);
}
puts("");
}
}
};

template <class DataType>
DataType fpow(DataType x,int n)
{
DataType res(1);
while (n) {
if (n&1) {
res=x*res%MO;
}
x=x*x%MO;
n>>=1;
}
return res;
}

int main()
{
int n,m;
Mat coop(6,6,1);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
coop.el[x][opps[y]]=0;
coop.el[y][opps[x]]=0;
}
coop=fpow(coop,n-1);
Mat cnt(6,1,1);
cnt=coop*cnt%MO;
ll ans=0,fo=4;
for (int i=1;i<=6;i++) {
ans=(ans+cnt.el[i][1])%MO;
}
ans=ans*fpow(fo,n)%MO;
printf("%I64d\n",ans);
return 0;
}
阅读全文 »

迎风一刀斩

看到这题的时候一脸懵逼。。。后来才发现原来旋转角度只有90度、180度、或270度。。。不过还是查了一下题解。。。

其实只有四种情况,只要会画就差不多会写了。

这里写图片描述

解释一下代码。。。
check()可以通过引用返回横向的长(X)短(x)边,纵向的长(Y)短(y)边,以及平行坐标轴的边数(strt)。
penta()本来是用来判断五边形和三角形的,后来发现前三个写起来都一样就都合在一起了。
quaqua()用来判断两个四边形能不能拼成矩形,其中两个矩形是一种特殊情况 ,如果一个的边长是(A, B),另一个是(X, Y),只要A/B中的一个和X/Y中的一个相等就可以了。
其他一般的情况都是通过图中的相等关系判断的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> PII;
PII a[6],b[6];

inline void input(PII a[],int &n)
{
scanf("%d",&n);
for (int i=0;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
a[i]=PII(x,y);
}
}

inline void check(PII a[],int n,int &X,int &x,int &Y,int &y,int &strt)
{
X=x=Y=y=strt=0;
for (int i=0;i<n;i++) {
if (a[i].first==a[(i+1)%n].first) {
strt++;
int tmp=abs(a[i].second-a[(i+1)%n].second);
if (tmp>Y) y=Y,Y=tmp;
else y=tmp;
} else if (a[i].second==a[(i+1)%n].second) {
strt++;
int tmp=abs(a[i].first-a[(i+1)%n].first);
if (tmp>X) x=X,X=tmp;
else x=tmp;
}
}
}

inline bool penta(int n,int m)
{
int x,X,y,Y,strt;
check(b,m,X,x,Y,y,strt);
if (strt!=m-1) return false;
int A=Y-y,B=X-x;
check(a,n,X,x,Y,y,strt);
if (strt!=n-1) return false;
return (X==A&&Y==B)||(X==B&&Y==A);
}

bool quaqua()
{
int x,X,y,Y,strt;
check(b,4,X,x,Y,y,strt);
if (strt<3) return false;
if (strt==4) {
int A=X,B=Y;
check(a,4,X,x,Y,y,strt);
if (strt!=4) return false;
return A==X||A==Y||B==X||B==Y;
}
int height,A,B;
if (y==0) {
height=Y;A=X;B=x;
} else {
height=X;A=Y;B=y;
}
check(a,4,X,x,Y,y,strt);
if (strt<3) return false;
if (y==0) {
return height==Y&&x+A==X+B;
} else {
return height==X&&y+A==Y+B;
}
}

int main()
{
int T,n,m;
scanf("%d",&T);
while (T--) {
input(a,n);
input(b,m);
if (n>m) {
swap(n,m);
swap(a,b);
}
bool f=false;
if (n==4&&m==4) f=quaqua();
else f=penta(n,m);
puts(f?"YES":"NO");
}
return 0;
}

独立写的代码一发过,很开心。

阅读全文 »

10. 最大比例

X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。

输入格式:
第一行为数字N(n<100),表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额
要求输出:
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数
测试数据保证了输入格式正确,并且最大比例是存在的。

例如,输入:
3
1250 200 32
程序应该输出:
25/4
再例如,输入:
4
3125 32 32 200
程序应该输出:
5/2
再例如,输入:
3
549755813888 524288 2
程序应该输出:
4/1

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。 所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意:
所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。

这题比较复杂,我们需要分析一下。
首先比值都是相邻级别的,所以我们可以将这n个数排序再去重,
(如果只剩一个数的话,那答案应该是无穷大,这里就不考虑了)
然后把相邻的比值都算出来,为了方便讨论,再进行排序去重。
得到一个序列,$f_0=q^{k_0}, f_1=q^{k_1}, \dots, f_{n-1}=q^{k_{n-1}}$,$k_i$ 严格递增。

如果我们真的知道$q$和这些整数$k$,那么答案就是$q^g$,其中$g$是所有$k$的最大公约数。
为什么呢?
因为我们要找的是一个$x$,使得 $\log_{q^x}f_i$ 均为整数,即$\frac{k_i}{x}\log_qq=\frac{k_i}{x}$均为整数,
显然$x$是所有$k$的约数,且$x$最大,所以所求的$x$就是$g$。

当然问题在于我们根本不知道$q$和这些$k$,但是我们很惊喜的看到了最大公约数。
这里我们可以借鉴辗转相减法的操作 辗转相减法资料
不妨取两个数,定义$Q(a,b)$是由$a,b$唯一确定的最大比例,
且$Q$定义在无序对上,即$Q(b,a)=Q(a,b)$。
那么$Q(a,b)=Q(q^x,q^y)=q^{gcd(x,y)}=Q(q^x,q^{y-x})=Q(a,\frac{b}{a})\quad a<b$
所以我们只需要重复这个“辗转相减法”就可以得到最后的答案。

具体实现的时候可以每次只操作相邻的两个比值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=110;
const ll MAX=1000000000000;
ll a[N];

ll gcd(ll a,ll b)
{
if (!b) return a;
return gcd(b,a%b);
}

struct Frac
{
ll up,dw;
Frac() {}
Frac(ll a,ll b) {
if (a==0) {
up=0;dw=1;
return;
}
ll g=gcd(a,b);
up=a/g;dw=b/g;
}
bool operator <(const Frac &b) const {
return up*b.dw<dw*b.up;
}
bool operator ==(const Frac &b) const {
return !((*this)<b)&&!(b<(*this));
}
Frac operator /(const Frac &b) {
return Frac(up*b.dw,dw*b.up);
}
void print() {
printf("%I64d/%I64d\n",up,dw);
}
} f[N];

int main()
{
int n;
scanf("%d",&n);
for (int i=0;i<n;i++) {
scanf("%I64d",&a[i]);
}
sort(a,a+n);
n=unique(a,a+n)-a-1;
for (int i=0;i<n;i++) {
f[i]=Frac(a[i+1],a[i]);
}
Frac ans(MAX,1);
while (n>1) {
sort(f,f+n);
if (f[0]<ans) ans=f[0];
n=unique(f,f+n)-f-1;
for (int i=0;i<n;i++) {
f[i]=f[i+1]/f[i];
}
}
if (f[0]<ans) ans=f[0];
ans.print();
return 0;
}
阅读全文 »

1. 网友年龄

某君新认识一网友。 当问及年龄时,他的网友说: “我的年龄是个2位数,我比儿子大27岁, 如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦. 请填写表示可能情况的种数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

小学奥数或者枚举一下:7

2. 生日蜡烛

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

等差数列,枚举首项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <bits/stdc++.h>
using namespace std;

int main()
{
for (int i=1;i<=100;i++) {
int sum=0,j=i;
while (sum<236) {
sum+=j++;
}
if (sum==236) {
printf("%d %d\n",i,j);
}
}
return 0;
}

我觉得枚举首项从1到100是比较合理的。。。有人说答案是236我觉得他可能没救了…
正确答案:26

3. 方格填数

如下的10个格子
方格
填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

阅读全文 »

Shell Necklace

有一个很显然的递推式:$dp[i]=\sum_{j=0}^{i-1} dp[j]a_{i-j}$,当然朴素的算法是$O(n^2)$,肯定过不了。观察这个式子,发现符合fft的形式(了解FFT),所以使用cdq分治+FFT(套路),复杂度为$O(nlog^{2}n)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <bits/stdc++.h>
using namespace std;
const double PI=acos(-1.0);
const int MO=313;
const int N=100010;
struct Complex {
double x,y;
Complex(double _x = 0.0,double _y = 0.0)
{
x = _x;
y = _y;
}
Complex operator -(const Complex &b)const
{
return Complex(x-b.x,y-b.y);
}
Complex operator +(const Complex &b)const
{
return Complex(x+b.x,y+b.y);
}
Complex operator *(const Complex &b)const
{
return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
}
} x[280000],y[280000];
int a[N],dp[N];

void change(Complex y[],int len)
{
int i,j,k;
for(i = 1, j = len/2; i <len-1; i++) {
if(i < j)swap(y[i],y[j]);
k = len/2;
while(j >= k) {
j -= k;
k /= 2;
}
if(j < k)j += k;
}
}
void fft(Complex y[],int len,int on)
{
change(y,len);
for(int h = 2; h <= len; h <<= 1) {
Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
for(int j = 0; j < len; j+=h) {
Complex w(1,0);
for(int k = j; k < j+h/2; k++) {
Complex u = y[k];
Complex t = w*y[k+h/2];
y[k] = u+t;
y[k+h/2] = u-t;
w = w*wn;
}
}
}
if(on == -1) {
for(int i = 0; i < len; i++)
y[i].x /= len;
}
}

void cdq(int l,int r)
{
if (l==r) {
dp[l]+=a[l];
dp[l]%=MO;
return;
}
int mid=(l+r)>>1;
cdq(l,mid);
int len1=mid-l+1;
int len2=r-l+1;
int len=1;
while (len<=len2) len<<=1;
for (int i=0;i<len1;i++) {
x[i]=Complex(dp[l+i],0);
}
for (int i=len1;i<len;i++) {
x[i]=Complex(0,0);
}
for (int i=0;i<len2;i++) {
y[i]=Complex(a[i],0);
}
for (int i=len2;i<len;i++) {
y[i]=Complex(0,0);
}
fft(x,len,1);
fft(y,len,1);
for (int i=0;i<len;i++) {
x[i]=x[i]*y[i];
}
fft(x,len,-1);
for (int i=mid+1;i<=r;i++) {
dp[i]+=round(x[i-l].x);
dp[i]%=MO;
}
cdq(mid+1,r);
}

int main()
{
int n;
while (scanf("%d",&n),n) {
for (int i=1;i<=n;i++) {
scanf("%d",&a[i]);
a[i]%=MO;
}
memset(dp,0,sizeof(dp));
dp[0]=1;
cdq(1,n);
printf("%d\n",dp[n]);
}
return 0;
}
阅读全文 »