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);

}