LA 5916(GCD Guessing Game-质数分组)

现在有一个数x,1 ≤ x≤ n,告诉你n,每次你可以猜一个数y,如果x==y则结束,否则返回gcd(x,y),问最少只要几次就可以保证猜出答案。

Input 

The input file contains several test cases, each of them as described below.

The input contains one integer n2$ \le$n$ \le$10000.

Output

For each test case, write to the output on a line by itself.

Output one integer -- the number of guesses Andrew will need to make in the worst case.

 

Sample Input

6

 

Sample Output

2

首先把所有n以内素分组,每次询问一组素数的积——根据Gcd的性质确定这个数

每次贪心拿一个大质数与一堆小质数配(最右*最左)

 

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN (10000)
#define eps (1e-9)
#define For(i,n) for(int i=1;i< =n;i++) #define ForD(i,n) for(int i=n;i;i--) #define Fork(i,k,n) for(int i=k;i<=n;i++) int n,a[MAXN],size=0; bool b[MAXN]; int main() { memset(b,0,sizeof(b));b[1]=1; Fork(i,2,MAXN) { if (!b[i]) b[i]=1,a[++size]=i; For(j,size) { if (i*a[j]>MAXN) break;
b[i*a[j]]=1;
if (!i%a[j]) break;
}
}
// For(i,100) cout< >n)
{
int i=0,head=1,tail=size;
while (a[tail]>n) tail--;
while (head< =tail) { int p=a[tail]; while (p*a[head]<=n) p*=a[head++]; tail--;i++; } cout<

 

BZOJ 1013([JSOI2008]球形空间产生器sphere-gauss消元练习)

1013: [JSOI2008]球形空间产生器sphere

Time Limit: 1 Sec  Memory Limit: 162 MB

Submit: 1181  Solved: 654

[Submit][Status][Discuss]

Description

有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。

Input

第一行是一个整数,n。 接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。

Output

有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。

Sample Input

2
0.0 0.0
-1.0 1.0
1.0 0.0

Sample Output

0.500 1.500

数据规模:
对于40%的数据,1<=n<=3
对于100%的数据,1<=n<=10
提示:给出两个定义:
1、 球心:到球面上任意一点距离都相等的点。
2、 距离:设两个n为空间上的点A, B的坐标为(a1, a2, …, an), (b1, b2, …, bn),则AB的距离定义为:dist = sqrt( (a1-b1)^2 + (a2-b2)^2 + … + (an-bn)^2 )

 

高斯消元

显然可以消成Σ(pi-qi)xi=1/2*Σ(pi^2-qi^2)

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN (10+10)
#define MAXAi (20000)
#define eps (0.0000001)
#define For(i,n) for(int i=1;i< =n;i++) double sqr(double x){return x*x;} int n; double a[MAXN][MAXN],f[MAXN][MAXN]={0.0}; int gauss() { For(i,n) { if (abs(f[i][i])abs(f[p][i])) j=p;
swap(f[p],f[i]);//Waiting for change
}
if (abs(f[i][i])>n;
For(i,n+1) For(j,n) cin>>a[i][j];
For(i,n) For(j,n) f[i][j]=a[i][j]-a[i+1][j],f[i][n+1]+=sqr(a[i][j])-sqr(a[i+1][j]);
For(i,n) f[i][n+1]/=2;
/*
For(i,n)
{
For(j,n+1) cout<

你能看得出这些问题共同的做法吗?1

Program 1:

Just The Mice NBUT1312

nbut1312把肉和老鼠分开,至少要描几条(网格)线?

Program 2:

k-road Prob

K-road从A点到B点走k次,每次只能向左,下,假定每个格子上都有一个整数,问能走过的最大的数的和是多少?

Program 3:

k-road Prob 2

K-road从A点到B点走k次,每次只能向左,下,假定每个格子上都有一个整数,问能走过的最大的数的积是多少?

Program 4

Catching Curl

bzoj1001这图相信大家都见过了XD……题目略

 

数位和乘积(高精组合数学)

Problem 3 数位和乘积(digit.cpp/c/pas)

【题目描述】

一个数字的数位和乘积为其各位数字的乘积。求所有的N位数中有多少个数的数位和乘积恰好为K。请注意,这里的N位数是可以有前导零的。比如01,02视为二位数,但是他们的数位和乘积都是0。

【输入格式】

一行两个整数N,K

【输出格式】

一个行一个整数表示结果。

【样例输入】

2 3

【样例输出】

2

【样例输入2】

2 0

【样例输出2】

19

【数据范围】

对于20%:N <= 6。

对于50%:N<=16

存在另外30%:K=0。

对于100%:N <= 50,0 <= K <= 10^9。

法1:

k=0时,ans=10^n-9^n

否则就用记忆化搜索填1..9的个数

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN (50+10)
#define F (10000)
int n,k;
struct highn
{
int len,a[900];
highn():len(1){memset(a,0,sizeof(a));}
highn(int x)
{
memset(a,0,sizeof(a));
int i=0;
while (x)
{
a[++i]=x%F;
x/=F;
}
len=i;
}
void print()
{
printf("%d",a[len]);
for (int i=len-1;i;i--)
{
// if (a[i]<10000) printf("0");
if (a[i]<1000) printf("0");
if (a[i]<100) printf("0");
if (a[i]<10) printf("0");
printf("%d",a[i]);
}

}
friend highn operator+(highn& a,highn& b)
{
highn c;
int maxlen=max(a.len,b.len);
for (int i=1;i< =maxlen;i++) { c.a[i]=c.a[i]+a.a[i]+b.a[i]; if (c.a[i]>F)
{
c.a[i+1]+=c.a[i]/F;
c.a[i]%=F;
}
}
c.len=maxlen+1;
while (!c.a[c.len]&&c.len>1) c.len--;
return c;

}
friend highn operator-(highn& a,highn& b)
{
highn c;
int maxlen=a.len;
for (int i=1;i< =maxlen;i++) { c.a[i]+=a.a[i]-b.a[i]; if (c.a[i]<0) { c.a[i+1]--; c.a[i]+=F; } } c.len=maxlen; while (!c.a[c.len]&&c.len>1) c.len--;
return c;
}
friend highn operator*(highn& a,highn& b)
{
highn c;
for (int i=1;i< =a.len;i++) { for (int j=1;j<=b.len;j++) { c.a[i+j-1]+=a.a[i]*b.a[j]; if (c.a[i+j-1]>F)
{
c.a[i+j]+=c.a[i+j-1]/F;
c.a[i+j-1]%=F;
}
}
}
c.len=a.len+b.len+1;
while (!c.a[c.len]&&c.len>1) c.len--;
return c;
}

};
highn pow2(highn a,int b)
{
highn c;
if (!b) return 1;
if (b%2)
{
c=pow2(a,b/2);
c=c*c;
c=c*a;
}
else
{
c=pow2(a,b/2);
c=c*c;
}
return c;
}
int a[11],tot,b[11];
highn ans,C[51][51];
void dfs(int deep,highn rel,int hasget)
{
if (n

法2:

f[i][j][k][l][m]表示填到第i个数,2,3,5,7分别用j,k,l,m个的方案数

考虑后面填1..9的情况(显然不可能填0)

Bug:n=50,C(n,m)最大为C(50,25),可用long long.

----

----

法3:

容易发现

k=2^a*3^b*5^c*7^d时才有解

而且5,7取了当且只当数位为5,7的情况.

2-2,4,6,8

3-3,6,9

5-5

7-7

故可只考虑2,3,不考虑5,7

f[i][j]k]表示i位,取了j个2和k个3后的方案数,

因为可以用1填充,

所以答案=∑f[p][j][k]*C(p,j+k)*C(n,a[5])*C(n-a[5],a[7]) (p<=n-a[5]-a[7])

BZOJ 1507(文字编辑器-块状链表)

1507: [NOI2003]Editor

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 922  Solved: 323
[Submit][Status][Discuss]

Description

很久很久以前,DOS3.x 的程序员们开始对 EDLIN 感到厌倦。于是,人们开始纷纷改用自己写的文本编辑器……
多年之后,出于偶然的机会,小明找到了当时的一个编辑软件。进行了一些简单的测试后,小明惊奇地发现:那个软件每秒能够进行上万次编辑操作(当然,你不能手工进行这样的测试)!于是,小明废寝忘食地想做一个同样的东西出来。你能帮助他吗?
为了明确任务目标,小明对“文本编辑器”做了一个抽象的定义:
文本:由 0 个或多个字符构成的序列。这些字符的 ASCII 码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。
光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。
文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下六条操作的程序。
如果这段文本为空,我们就说这个文本编辑器是空的。

你的任务是:
 建立一个空的文本编辑器。
 从输入文件中读入一些操作指令并执行。
 对所有执行过的 GET 操作,将指定的内容写入输出文件。

Input

第一行是指令条数 t,以下是需要执行的 t 个操作。其中:
为了使输入文件便于阅读,Insert 操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。
除了回车符之外,输入文件的所有字符的 ASCII 码都在闭区间[32, 126]内。且行尾没
有空格。
这里我们有如下假定:
1. MOVE 操作不超过 50000 个,INSERT 和 DELETE 操作的总个数不超过 4000,PREV 和 NEXT 操作的总个数不超过 200000。
2. 所有 INSERT 插入的字符数之和不超过 2M(1M=1024*1024),正确的输出文件长度不超过 3M 字节。
3. DELETE 操作和 GET 操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。
4. 输入文件没有错误。
对 C++选手的提示:经测试,对最大的测试数据使用 fstream 进行输入有可能会比使用 stdio 慢约 1 秒,因此建议在可以的情况下使用后者。

Output

输出每行依次对应输入文件中每条GET指令的输出。

Sample Input

15
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 16
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
.\/.
Get 4
Prev
Insert 1
^
Move 0
Get 22

Sample Output

.\/.
abcde^_^f.\/.ghijklmno

这题我是用块状链表做的

块状链表的复杂度大约是O(√n)

一定要尽可能将块分成长度为√tot的,balance()时要把所有的长度分为介于1/2√tot-2√tot之间

另外merge时要注意先把cur移动再重载合并格的长度(不容易查出错,不知为何,加错也能过8个点)

要参考老董的讲解nocow的模板

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXP (1024*1024)
#define MAXN (2900)
struct block
{
int n;
char a[MAXN];
block *next,*pre;
block():n(0){next=pre=NULL;}
}*first;
block* q[MAXN];
int size=0,tot=0;
void del(block *x)
{
q[++size]=x;
if (x->pre) x->pre->next=x->next;
if (x->next) x->next->pre=x->pre;
if (x==first) first=x->next;
}
block *newblock()
{
if (size) return q[size--];
block *x=new block();
return x;
}
void link(block *a,block *b)
{
if (a) a->next=b;
if (b) b->pre=a;
}
void spilt(block *x,int nowsize)
{
if (!nowsize||nowsize==x->n) return;
block *tmp=x->next;
x->next=newblock();
block *x2=x->next;
x2->n=x->n-nowsize;
for (int i=1;i< =x2->n;i++) x2->a[i]=x->a[nowsize+i];
x->n=nowsize;
link(x2,tmp);
link(x,x2);
}
struct cursor
{
int n;
block *ll;
cursor():n(0){ll=first; }
void pre()
{
n--;
if (n<0)
{
ll=ll->pre;
n=ll->n-1;
}
}
void next()
{
n++;
if (n>ll->n)
{
ll=ll->next;
n=1;
}
}
void move(int k)
{
n=k,ll=first;
while (n>ll->n)
{
n-=ll->n;
ll=ll->next;
}
}
}cur;
void get(cursor cur,int k)
{
int p=cur.ll->n-cur.n;
if (p>=k)
{
for (int i=cur.n+1;i< =cur.n+k;i++) printf("%c",cur.ll->a[i]);
}
else
{
for (int i=cur.n+1;i< =cur.ll->n;i++) printf("%c",cur.ll->a[i]);
cur.ll=cur.ll->next;cur.n=0;
get(cur,k-p);
}
}
void merge(block *x)
{
if (!x->next) return;
for (int i=1;i< =x->next->n;i++) x->a[x->n+i]=x->next->a[i];
if (cur.ll==x->next)
{
cur.ll=x;
cur.n+=x->n;
}
x->n+=x->next->n;
del(x->next);
}
void balance()
{
int maxsize=min(MAXN,(int)sqrt(tot)*2);
int minsize=(int)sqrt(tot)/2;
block *x=first;
while (x)
{
while (x->nn>maxsize)
{
if (x->n
next) break;
// get(cur,1);
}
else
{
spilt(x,(x->n)>>1);
if (cur.ll==x&&cur.n>cur.ll->n)
{
cur.n-=cur.ll->n;
cur.ll=cur.ll->next;
}
// get(cur,1);
}
}
x=x->next;
}
}
void delet(int k)
{
if (!k) return;
if (cur.n)
{
spilt(cur.ll,cur.n);
cur.ll=cur.ll->next; cur.n=0;
}
while (k>cur.ll->n)
{
del(cur.ll);
k-=cur.ll->n;
cur.ll=cur.ll->next;
// cur.n=0;
}
if (k==cur.ll->n)
{
cur.ll->n=0;
}
else
{
spilt (cur.ll,k);
delet(k);
}
balance();
}
void insert(int k)
{
block *l=newblock();*l=block();
block *r=l;
int maxsize=min(MAXN,(int)sqrt(tot));
for (int i=1;i< =k;i++) { char c; for (scanf("%c",&c);(c<32)||(c>126)||(c=='\n');scanf("%c",&c));
if (r->n>maxsize)
{
block *tmp=r;
r=newblock();*r=block();link(tmp,r);
}
r->a[++r->n]=c;
}
if (cur.n)
{
spilt(cur.ll,cur.n);
block *tmp=cur.ll->next;
link(cur.ll,l),link(r,tmp);
}
else
{
link(cur.ll->pre,l),link(r,cur.ll),cur.ll=l;
if (first->pre) first=l;
}
balance();
}
int main()
{
first=newblock();cur.ll=first;
int t;scanf("%d",&t);
while (t--)
{
char s[10];
scanf("%s",s);
int k;
switch(s[0])
{
case'M':scanf("%d",&k);cur.move(k);break;
case'I':scanf("%d",&k);tot+=k;insert(k);break;
case'D':scanf("%d",&k);tot-=k;delet(k);break;
case'G':scanf("%d",&k);get(cur,k);printf("\n");break;
case'P':cur.pre();break;
case'N':cur.next();break;
}
// get(cursor(),tot);cout<