|
||||||||||||||||||||
Number (dp-性质数状态表示)
Number
【题目描述】
明明在做力学作业的时候发现一类数非常有趣,他们和杠杆有比较相似的结构。这类数有这样的性质:
把某一位当成支点的话,那么左边的数字到这个点的力矩和等于右边的数字到这个点的力矩和,力矩可以理解为距离乘以数字。
举个例子,4139就是满足条件的数字,把3当成支点,我们有这样的等式4 * 2 + 1 *1 = 9 * 1。
小明想知道在一个区间[x,y]中,有多少个这样的数。
【输入数据】
两个数,表示x,y。 0 <= x,y<= 1018。
【输出数据】
一个输出,表示区间[x,y]中满足条件的数的个数。
【样例输入】
7604 24324
【样例输出】
897
【数据范围】
0 <= x,y<= 1018
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXS 810 + 10 +4000
#define MAXx 1000000000000000000
#define MAXI 30
long long f[MAXI][MAXS][2],depth,a[MAXI],ans,pos;
//0 <= 只能取<=第i位的数,否则超过X越界 1 高位已经取了更小的 位数 后面随便取
long long dfs(int i,int s,int c)
{
if (s<0||s>MAXS) return 0;
if ((i==0)&&((s)||(c))) return 0;
if (i==0) {//cout<<i<<' '<<s<<' '<<c<<' '<<f[i][s][c]<<endl;
return 1;}
// cout<<i<<' '<<s<<' '<<c<<' '<<f[i][s][c]<<endl;
if (f[i][s][c]>=0) return f[i][s][c];
else f[i][s][c]=0;
if (!c)
{
// cout<<"push "<<a[i]<<endl;
f[i][s][c]+=dfs(i-1,s-(pos-i)*a[i],0);
}
else
{
for (int k=0;k<a[i];k++) //{ cout<<"push "<<k<<endl;
f[i][s][c]+=dfs(i-1,s-(pos-i)*k,0); // cout<<"pop "<<k<<endl;}
for (int k=0;k<=9;k++)//{ cout<<"push "<<k<<endl;
f[i][s][c]+=dfs(i-1,s-(pos-i)*k,1); //cout<<"pop "<<k<<endl;}
}
return f[i][s][c];
}
long long calc(long long x)
{
if (!x) return 0; //<0的杠杆数为0
long long ans=0;
memset(f,0,sizeof(f));
depth=0;
while (x)
{
depth++;
a[depth]=x%10;
x=x/10;
}
for (int i=1;i<=depth/2;i++)
{
swap(a[i],a[depth-i+1]);
}
ans=0;
f[depth+1][0][0]=1; // =29333
f[depth+1][0][1]=1; // <29333
for (pos=1;pos<=depth;pos++)
{
memset(f,128,sizeof(f));
// cout<<f[19][0][0]<<endl;
ans+=/*dfs(depth,0,0)+*/dfs(depth,0,1);
ans--; //不考虑 0 它无论支点为几都出现
}
return ans+1; //最后 加上 0
/*
f[i][s][c]=f[i-1][s-(k-i)*j][0]
*/
}
int main()
{
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
long long x,y;
scanf("%lld%lld",&x,&y);
printf("%lld",calc(y+1)-calc(x));
// while (1);
}
POJ 3049(输出字母)
在一堆字母中找一段字母,使其中至少含有1个原音,2个辅音字母,且按字典序从小到大排列
果断搜
Program P3049;
var
n,i,j,m:longint;
a:array[1..26] of char;
b:array['a'..'z'] of boolean;
c:char;
procedure swap(var a,b:char);
var
t:char;
begin
t:=a;a:=b;b:=t;
end;
procedure dfs(father:longint;s:string;flag:boolean;l:longint);
var
i:longint;
begin
if l=n then
begin
if flag then writeln(s);
exit;
end;
for i:=father+1 to m-(n-l)+1 do
dfs(i,s+a[i],flag or b[a[i]],l+1);
end;
begin
fillchar(b,sizeof(b),false);
b['a']:=true;b['e']:=true;b['i']:=true;b['o']:=true;b['u']:=true;
readln(n,m);
for i:=1 to m do
begin
read(a[i]);
read(c);
end;
for i:=1 to m-1 do
for j:=i+1 to m do
if ord(a[i])>ord(a[j]) then swap(a[i],a[j]);
if n<3 then halt;
dfs(0,'',false,0);
end.
POJ 2456(二分哲学)
这题普通的二分会T…………
法一:只循环60遍,用ans记录答案(见标程)
法二:进行特判,若l+1==r 则 m=(l+r+1) shl 1 否则 m=(l+r) shl 1
Program P2456;
const
maxd=1000000000;
maxn=100000;
var
n,c,i,j,k:longint;
a:array[1..maxn] of longint;
procedure sort(l,r:longint);
var
m,i,k,head,tot,ans:longint;
begin
for k:=1 to 60 do
begin
m:=(l+r) shr 1;
head:=1;tot:=0;
for i:=2 to n do
begin
if a[i]-a[head]>=m then
begin
inc(tot);
head:=i;
end;
end;
if tot>=c-1 then begin ans:=m; l:=m+1 end else r:=m-1;
end;
writeln(ans);
end;
procedure qsort(l,r:longint);
var
i,j,m,p:longint;
begin
i:=l;
j:=r;
m:=a[(l+r) shr 1];
repeat
while a[i]<m do inc(i);
while a[j]>m do dec(j);
if i<=j then
begin
p:=a[i];a[i]:=a[j];a[j]:=p;
inc(i);dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
begin
read(n,c);
for i:=1 to n do read(a[i]);
qsort(1,n);
sort(1,maxd);
end.
POJ 3289(高精度乘法)
高精度乘法
Program P3289;
const
maxn=40000;
F=10;
type
arr=record
d:array[1..maxn] of longint;
len,doc:longint;
end;
var
r,m:arr;
y:longint;
i:longint;
a,b:arr;
function max(a,b:longint):longint;
begin
if a<b then exit(b) else exit(a);
end;
procedure multipy(a,b:arr;var c:arr);
var
i,j,len:longint;
begin
fillchar(c,sizeof(c),0);
c.len:=a.len+b.len;
for i:=1 to a.len do
for j:=1 to b.len do
begin
inc(c.d[i+j-1],a.d[i]*b.d[j]);
inc(c.d[i+j],c.d[i+j-1] div F);
c.d[i+j-1]:=c.d[i+j-1] mod F;
end;
while (c.d[c.len]=0) and (c.len>1) do dec(c.len);
c.doc:=a.doc+b.doc;
end;
procedure to_arr(doc:longint;var c:arr);
var
x,i,n:longint;
begin
read(x);
i:=0;
while (x>0) do
begin
inc(i);
c.d[i]:=x mod F;
x:=x div F;
end;
c.len:=i;
c.doc:=doc;
end;
Procedure jie(a:arr;x:longint;var c:arr);
begin
if x=1 then begin c:=a; exit; end;
fillchar(c,sizeof(c),0);
if (x mod 2=0) then
begin
jie(a,x div 2,c);
multipy(c,c,c);
end
else
begin
jie(a,x div 2,c);
multipy(c,c,c);
multipy(a,c,c);
end;
end;
begin
to_arr(2,r);
r.len:=3;r.d[3]:=1;
to_arr(0,m);
read(y);
jie(r,y,r);
multipy(m,r,m);
for i:=m.len downto m.doc+1 do write(m.d[i]);
writeln;
end.
POJ 2390 (小数高精度乘法)
小数高精度乘法
m*(1+r/100)^y
Program P2390;
const
maxn=40000;
F=10;
type
arr=record
d:array[1..maxn] of longint;
len,doc:longint;
end;
var
r,m:arr;
y:longint;
i:longint;
a,b:arr;
function max(a,b:longint):longint;
begin
if a<b then exit(b) else exit(a);
end;
procedure multipy(a,b:arr;var c:arr);
var
i,j,len:longint;
begin
fillchar(c,sizeof(c),0);
c.len:=a.len+b.len;
for i:=1 to a.len do
for j:=1 to b.len do
begin
inc(c.d[i+j-1],a.d[i]*b.d[j]);
inc(c.d[i+j],c.d[i+j-1] div F);
c.d[i+j-1]:=c.d[i+j-1] mod F;
end;
while (c.d[c.len]=0) and (c.len>1) do dec(c.len);
c.doc:=a.doc+b.doc;
end;
procedure to_arr(doc:longint;var c:arr);
var
x,i,n:longint;
begin
read(x);
i:=0;
while (x>0) do
begin
inc(i);
c.d[i]:=x mod F;
x:=x div F;
end;
c.len:=i;
c.doc:=doc;
end;
Procedure jie(a:arr;x:longint;var c:arr);
begin
if x=1 then begin c:=a; exit; end;
fillchar(c,sizeof(c),0);
if (x mod 2=0) then
begin
jie(a,x div 2,c);
multipy(c,c,c);
end
else
begin
jie(a,x div 2,c);
multipy(c,c,c);
multipy(a,c,c);
end;
end;
begin
to_arr(2,r);
r.len:=3;r.d[3]:=1;
to_arr(0,m);
read(y);
jie(r,y,r);
multipy(m,r,m);
for i:=m.len downto m.doc+1 do write(m.d[i]);
writeln;
end.
不等数列 (Dp插入e)
【题目描述】
将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2012取模。
【输入格式】
第一行2个整数n,k。
【输出格式】
一个整数表示答案。
【样例输入】
5 2
【样例输出】
66
【数据范围】
对于30%的数据:n <= 10
对于100%的数据:k < n <= 1000,
F[i,j]=f[i-1,j](j+1)+f[i-1][j-1](i-j) i表示从1到i的数 j表示小于号个数
插入最大数e后添了一个>
或者一个<的数量
const maxn=1000; var f:array[0..1000,0..1000] of longint; n,i,j,k:longint; begin assign(input,'num.in'); assign(output,'num.out'); reset(input); rewrite(output); read(n,k); if (k>n-1-k) then k:=n-1-k; for i:=1 to n do begin f[i,0]:=1; f[i,i-1]:=1; end; for i:=2 to n do for j:=1 to k do f[i,j]:=(f[i-1,j]*(j+1)+f[i-1,j-1]*(i-j)) mod 2012; writeln(f[i,k]); close(input); close(output); end.
另附 暴搜%30数据的版本
var
b:array[1..10] of boolean;
f:array[0..10] of longint;
n,k,i:longint;
procedure dfs(l,x,father:longint);
var
i:longint;
begin
if l=n then begin inc(f[x]); exit; end;
for i:=1 to n do
if not(b[i]) then
begin
b[i]:=true;
if father<i then dfs(l+1,x+1,i) else
dfs(l+1,x,i);
b[i]:=false;
end;
end;
begin
readln(n,k);
fillchar(b,sizeof(b),false);
fillchar(f,sizeof(f),0);
for i:=1 to n do
begin
b[i]:=true;
dfs(1,0,i);
b[i]:=false;
end;
for i:=0 to n-1 do write(f[i],' ');
end.
RQNOJ 658(观光公交)
几大注意点:
1.一次使用氦气加速器会把后面分成好几段。
2.我们仅维护end[i],wait[i]恒定,因此需提前让wait[i]=max(wait[i-1],wait[i]);
3.w[i]+w[i+1]+...+w[j],且w恒定,故可预处理sum[i](满足累加性)
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<functional>
#include<iostream>
#define MAXN 1000 +10
#define MAXM 10000 + 10
#define MAXK 100000 + 10
#define MAXD 100 + 10
#define MAXT 100000 + 10
using namespace std;
struct man
{
int t,l,r;
}t[MAXM];
struct interval
{
int l,r,w;
};
int n,m,k,ans,d[MAXN+1],wait[MAXN+1],w[MAXN+1],end[MAXN+1],sum[MAXN+1];
bool operator<(const interval a,const interval b) //重载 operator < 的意思 为q做准备
{
return a.w<b.w;
}
priority_queue<interval> q; //priority_queue<Node, vector<Node>, greater<Node> >; 完整的不能用
void push(int l,int r)
{
bool flag=0;
for (int i=l;i<r;i++) if (d[i]) {flag=1;break;}
if (!flag) return;
int tot=sum[r]-sum[l];
if (!tot) return ;
interval now;
now.w=tot;
now.l=l;
now.r=r;
q.push(now);
// cout <<"add "<< now.l << ' ' << now.r <<' '<< now.w << endl;
}
int main()
{
// freopen("qc.in","r",stdin);
memset(wait,0,sizeof(wait));
memset(w,0,sizeof(w));
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n-1;i++)
scanf("%d",&d[i]);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&t[i].t,&t[i].l,&t[i].r);
wait[t[i].l]=max(wait[t[i].l],t[i].t);
w[t[i].r]++;
}
end[1]=0;
for (int i=2;i<=n;i++)
end[i]=max(end[i-1],wait[i-1])+d[i-1];
ans=0;
for (int i=1;i<=m;i++)
ans+=end[t[i].r]-t[i].t;
sum[1]=sum[0]=0;
for (int i=2;i<=n;i++) {sum[i]=sum[i-1]+w[i]; wait[i]=max(wait[i-1],wait[i]);}
// for (int i=0;i<=n;i++) cout<<end[i]<<' ';
// cout<<endl;
int tot=d[1],head=1;
for (int i=2;i<=n;i++)
{
if (wait[i]>=end[i])
{
if (tot) push(head,i);
tot=0;
head=i;
}
tot+=d[i];
/*
tot+=w[i]*min(1,d[i]);
// tot+=w[i];
*/
}
if (tot) push(head,n);
//00 cout<<ans<<endl;
//贪心
// sort(t+1,t+m+1,cmp);
// 调试
/* while( !q.empty() ){
cout << q.top().l << ' ' << q.top().r <<' '<< q.top().w << endl;
q.pop();
}
*/
/*
for (int i=1;i<=n;i++)
{
cout<<end[i]<<' ';
}
*/
while (k&&!q.empty())
{
/* cout<<"/////////"<<endl;
for (int i=1;i<=n;i++)
{
cout<<end[i]<<' ';
}
cout<<endl;
for (int i=1;i<=n;i++)
{
cout<<wait[i]<<' ';
}
cout<<endl;
*/
interval now=q.top();
q.pop();
ans-=now.w;
int i=now.l;
//000
// cout << now.l << ' ' << now.r <<' '<< now.w << endl;
// cout << ans << endl;
//000
while (!d[i]) i++;
d[i]--;
int head=i,tot=0,i2=0;
i++;
while (i<=now.r/*&&wait[i]<end[i]*/)
{
// tot+=w[i-1];
end[i]--;
//000
// for (int cse=1;cse<=n;cse++) cout<<end[cse]<<',';
// cout<<endl;
//-
// cout<<i<<endl;
// cout<<wait[i+1]<<' '<<end[i+1]<<endl;
if (wait[i]==end[i])
{push(head,i);head=i;}
i++;
}
i--;
if (head!=now.r) push(head,now.r);
/*
if (i>now.r) {cout<<"smile"<<endl;
cout<<'<'<<' '<<i<<' '<<wait[i]<<' '<<end[i]<<' '<<endl;}
*/
// cout<<"i2:"<<i2<<endl;
/* if (i2) i=i2;
i--;
push(head,i);
if (i<now.r)
{
// if (!d[head]) tot+=w[head];
push(i,now.r);
}
*/
//处理 end[i] 显然最多影响到 now.r
k--;
}
cout<<ans<<'n';
// 调试
/*
while( !q.empty() ){
cout << q.top().l << ' ' << q.top().r <<' '<< q.top().w << endl;
q.pop();
}
for (int i=1;i<=n;i++)
{
cout<<end[i]<<' ';
}
*/
// while (1);
}
POJ 3661(贝茜晨练)
经典Dp,果断记忆化……
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<functional>
using namespace std;
#define MAXN 10000 + 10
#define MAXM 500 + 10
int f[MAXN][MAXM],n,m,d[MAXN];
int dfs(int i,int j)
{
if (i==0) return 0;
if (f[i][j]) return f[i][j];
if (i&&!j) f[i][j]=dfs(i-1,0);
if (j)
f[i][j]=dfs(i-1,j-1)+d[i];
else
{
for (int k=min(i,m);k>0;k--)
{
f[i][j]=max(f[i][j],dfs(i-k,k));
}
}
return f[i][j];
}
int main()
{
// freopen("running.in","r",stdin);
memset(f,0,sizeof(f));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&d[i]);
printf("%dn",dfs(n,0));
// while (1);
return 0;
}
POJ 3575(计算几何与二分-无尽的小数处理)
这题 写了将近半个月……总是在D各种Bug
总的说来-这题最难应该是在精度处理上
1
1
0 0 1
这组数据过了就说明精度处理差不多了……
Program kingdom;
const
maxn=100;
maxm=100;
le=0.000000001;
type
circle=record
x,y,r:double;
end;
var
s:array[1..maxn,1..1000] of circle;
n,i,j,k:longint;
m:array[1..maxn] of longint;
ans:array[1..maxn,1..4] of double;
wanted:array[1..maxn] of double;
b:array[1..maxn] of boolean;
l,r:double;
function arccos(cosa:double):double;
var
sina,tana:double;
begin
if cosa=0 then exit(pi/2);
sina:=sqrt(1-sqr(cosa));
tana:=sina/cosa;
exit(arctan(tana));
end;
function min(a,b:double):double;
begin
if a<b then exit(a) else exit(b);
end;
function max(a,b:double):double;
begin
if a>b then exit(a) else exit(b);
end;
function sector(a,r:double):double;
begin
exit(a*r*r/2);
end;
function triangle(a,r:double):double;
begin
exit(sin(a)*r*r/2);
end;
function inlside(s:circle;l:double):boolean;
begin
if (s.x-s.r>l) or (abs(s.x-s.r-l)<le) then exit(true) else exit(false);
end;
function inrside(s:circle;r:double):boolean;
begin
if (s.x+s.r<r) or (abs(s.x+s.r-r)<le) then exit(true) else exit(false);
end;
function intarea(s:circle;l,r:double):double;
var
i,j:longint;
a,a2,s1,s2,s3,s4:double;
bl,br:boolean;
begin
if (r<s.x-s.r) or (s.x+s.r<l) then exit(0);
if (s.x<=l) then
begin
a:=arccos((l-s.x)/s.r)*2;
if (abs(s.x-l)<le) then s1:=0
else s1:=triangle(a,s.r);
s2:=sector(a,s.r);
if s.x+s.r>r then
begin
a:=arccos((r-s.x)/s.r)*2;
s3:=sector(a,s.r);
s4:=triangle(a,s.r);
s2:=s2-(s3-s4);
end;
exit(s2-s1);
end
else
if (s.x>=r) then
begin
a:=arccos((s.x-r)/s.r)*2;
if (abs(s.x-r)<le) then s1:=0
else s1:=triangle(a,s.r);
s2:=sector(a,s.r);
if s.x-s.r<l then
begin
a:=arccos((s.x-l)/s.r)*2;
s3:=sector(a,s.r);
s4:=triangle(a,s.r);
s2:=s2-(s3-s4);
end;
exit(s2-s1);
end
else
begin
bl:=inlside(s,l);
br:=inrside(s,r);
if bl and br then exit(pi*s.r*s.r);
if bl and not(br) then
begin
a:=arccos((r-s.x)/s.r)*2;
s3:=sector(a,s.r)-triangle(a,s.r);
exit(pi*s.r*s.r-s3);
end;
if not(bl) and br then
begin
a:=arccos((s.x-l)/s.r)*2;
s3:=sector(a,s.r)-triangle(a,s.r);
exit(pi*s.r*s.r-s3);
end;
a:=arccos((s.x-l)/s.r)*2;
a2:=arccos((r-s.x)/s.r)*2;
s1:=sector(2*pi-a-a2,s.r);
s2:=triangle(a,s.r)+triangle(a2,s.r);
exit(s1+s2);
end;
end;
function place(k:longint;l,r:double):boolean;
var
tot:double;
i,j:longint;
begin
tot:=0;
for j:=1 to m[k] do
begin
tot:=tot+intarea(s[k,j],l,r);
end;
// writeln(tot*n,' ',wanted[k]*pi);
if (abs(tot*n-wanted[k]*pi)<le) then exit(true);
if (tot*n<(wanted[k]*pi)) then exit(false) else exit(true);
end;
function bsearch(r1,r2:double):double;
var
m:double;
i,j,k,num:longint;
flag:boolean;
begin
for k:=1 to 60 do
begin
flag:=false;
m:=(r1+r2)/2;
for i:=1 to n do
if not b[i] then
begin
flag:=flag or place(i,l,m);
if flag then
begin
num:=i;
break;
end;
end;
if flag then r2:=m else r1:=m;
end;
b[num]:=true;
ans[num,1]:=l;
ans[num,2]:=r1;
exit(r1);
end;
begin
{ assign(input,'kingdom.in');
reset(input);
} r:=-10000;
l:=10000;
read(n);
fillchar(b,sizeof(b),false);
fillchar(wanted,sizeof(wanted),0);
for i:=1 to n do
begin
read(m[i]);
for j:=1 to m[i] do
begin
read(s[i,j].x,s[i,j].y,s[i,j].r);
// writeln(s[i,j].x,s[i,j].y,s[i,j].r);
r:=max(r,s[i,j].x+s[i,j].r);
l:=min(l,s[i,j].x-s[i,j].r);
wanted[i]:=wanted[i]+sqr(s[i,j].r);
end;
end;
r:=r+1;
for i:=1 to n do
l:=bsearch(l,r);
for i:=1 to n do
begin
writeln('4');
writeln(ans[i,1]:7:7,' 3000');
writeln(ans[i,1]:7:7,' -3000');
writeln(ans[i,2]:7:7,' -3000');
writeln(ans[i,2]:7:7,' 3000');
end;
// close(input);
end.