2.14 count257 2016D2

关于取模 注意取模等于零!!!

T1组合数问题

关于本题:

1.组合数杨辉三角!!!杨辉第二遍卡我!!!

杨辉三角注意初始化问题!!!

2.两维数组前缀和公式·和·传递

首先明显地,这题我们要求组合数,那就必须用到组合数的递推公式:C(i,j)=C(i-1,j)+C(i-1,j-1),其实就是杨辉三角的递推式。

因为要满足是k的倍数,因此枚举所有范围内的组合数,对k取模就可以直接判断了。

*以下,满足条件的组合数指能被k整除的组合数(既是k的倍数的组合数个数)

不过,为了提高效率,我们可以进行进一步的优化,就是预处理出组合数从而求出所有区间的满足条件的组合数个数,这里就要用到二维前缀和。

设a[i][j]为在C([1,i](从1到i),[1,j](从1到j))内满足条件的组合数个数,初始时,在算组合数C(i,j)时对其mod k,若得0则被k整除,a[i][j]=1;在递推时,类似于一维前缀和,a[i][j]应当对于i和j分别递推,即传递a[i-1][j]和a[i][j-1]的值,由容斥原理可得:a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];这是因为a[i-1][j]和a[i][j-1]都包含了a[i-1][j-1],因此a[i-1][j-1]被加了两次,故要减去一次。
——————— 
作者:Forward_Star 
来源:CSDN 
原文:https://blog.csdn.net/weixin_39872717/article/details/78165946 
版权声明:本文为博主原创文章,转载请附上博文链接!

100100分 前缀和+递推打表
大家知道,即使打过表,算法的复杂度其实还多的一维,也就是这反复查询让人难以想到,使得我死死卡在95分一整天,才又翻了题解。
前缀和,有效减少查询统计时的复杂度,每一次查询O(n)O(n)降到$O(1),绝对过的了
记住:上加左 减左上 加自己
ans[i][j]=ans[i][j-1]+ans[i-1][j]-ans[i-1][j-1]ans[i][j]=ans[i][j−1]+ans[i−1][j]−ans[i−1][j−1]”
(敲黑板)

inline void build()
{
  c[0][0]=1;
  c[1][0]=c[1][1]=1;
  for(int i=2;i<=2000;i++)
  {
    c[i][0]=1;
    for(int j=1;j<=i;j++)
    {
      c[i][j]=(c[i-1][j-1]+c[i-1][j])%k;
      ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];//前缀和。
      if(!c[i][j])ans[i][j]++;//如果满足结论,计数加一。(有没有感觉很像我的玄学优化)
    }
    ans[i][i+1]=ans[i][i];//继承。
  }
}
inline void solve()
{
  t=read(),k=read();
  build();
  while(t--)
  {
    n=read(),m=read();
    if(m>n)printf("%lld\n",ans[n][n]);//如果m>n,ans只会达到n,只需输出ans[n,n]就可以了。
    else printf("%lld\n",ans[n][m]);
  }
}

 

ybx’s 代码很有道理的样子……

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,t,k,ans[2100][2100];
int f[2100][2100];
int main(){
	scanf("%d%d",&t,&k);
	for(int i=0;i<=2000;i++) f[i][0]=1;
	
    for(int i=1;i<=2000;i++)
      for(int j=1;j<=i;j++){
      	f[i][j]=(f[i-1][j]+f[i-1][j-1])%k;
      	if(!f[i][j]) ans[i][j]=ans[i][j-1]+1;
      	else ans[i][j]=ans[i][j-1];
	  }
    	
	while(t--){
		int ans1=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) 
		 if(m>i) ans1+=ans[i][i];
		else ans1+=ans[i][m];
		 printf("%d\n",ans1);    
	}
    
	return 0;
}

ans【i】【j】为第i行前j个有多少个符合要求。

T2 蚯蚓

优先队列看出来也不会写……

关键点: 发现此题中隐含的单调性.

“  

         首先这道题可以用合并果子的思路做, 合并果子是找到两个最小的并合并, 而这道题是找到最大的拆分.实际上是差不多的.

  如何处理每次的将每只蚯蚓加一定长度呢?或许可以转变思路, 每次只有两只蚯蚓没被加其他的全部被加了, 根据运动是相互的, 除了那被切成的两只蚯蚓其他的都往正方向移动了一些, 等价于那两只往负方向移动了一些. 所以可以记录累计加的长度, 有几只没被加的就减去就好了.

         发现先被切掉的蚯蚓分成的蚯蚓一定比后切掉的蚯蚓分成的蚯蚓大.   假设这两只蚯蚓分别为a,ba,b,其中a>ba>b.那么它被切成a_1,a_2a1​,a2​. t秒后, bb被切成了b_1,b_2b1​,b2​.此时a_1,a_2a1​,a2​的长度为l_{a_1}+t=pl_{a}+t,l_{a_2}+t=(1-p)l_a+tla1​​+t=pla​+t,la2​​+t=(1−p)la​+t.而b_1,b_2b1​,b2​的长度却为p(l_b+t),(1-p)(1_b+t)p(lb​+t),(1−p)(1b​+t), 容易看出l_{a_1}>l_{b_1},l_{a_2}>l_{b_2}la1​​>lb1​​,la2​​>lb2​​.也就是说根本不需要用一个堆来维护, 它本来就具有一定单调性.

  那么就是说如果蚯蚓a_1,a_2,\cdots,a1​,a2​,⋯,满足a_1>a_2>\cdotsa1​>a2​>⋯,那么以此分成两只a_{11},a_{12},a_{21},a_{22},\cdotsa11​,a12​,a21​,a22​,⋯.那么a_{12}>a_{22}>\cdots,a_{11}>a_{21}>\cdotsa12​>a22​>⋯,a11​>a21​>⋯

  那么就可以将这两堆依次存储, 加上还没被切过的蚯蚓.每次要切时在这三堆里面选择最大的, 切完再依次放回去.   所以这么做时间复杂度为O(m)O(m).再优化一下细节基本上就没问题了.

  结论: 善于发现题目中隐含的单调性.

  Tip:有些细节需要仔细考虑不然会很惨         ”

头文件

初始

int main() {
	输入
	now排序
	int top;
	for(int i=1;i<=m;i++) {
		找最长的蚯蚓
		切 ,存 ,变长  ***注意不切当前要加上sigma再切!
		适时输出
	}
	三个数组用优先队列合并排序
    输出
    return 0;
} 
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#define N 7000005
using namespace std;

bool cmp(const int &a,const int &b){
    return a>b;
}

priority_queue<int>ans;
int cut1[N],now[N],cut2[N];
int n,m,q,u,v,t;
int sigma;
double p;
int h,h1,h2;
int t0,t1,t2;

int main() {
	scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
	p=(double)u/v;
	int tmp;
	for(t0=1;t0<=n;++t0) 
		scanf("%d",&now[t0]);
	t0--;
	t1=t2=0;h=h1=h2=1;
	sort(now+1,now+t0+1,cmp);
	int top;

	for(int i=1;i<=m;i++) {
		if(h>t0) {	if(cut1[h1]>cut2[h2]) 	top=cut1[h1++];
			            else top=cut2[h2++]; }
		else if(now[h]>=cut1[h1]&&now[h]>=cut2[h2]) top=now[h++];
		else if(cut1[h1]>=cut2[h2]&&cut1[h1]>=now[h]) top=cut1[h1++];
		else top=cut2[h2++];

		top+=sigma;
		int a1=floor(p*(double)top),a2=top-a1;
		sigma+=q;
		a1-=sigma;a2-=sigma;
		cut1[++t1]=a1;cut2[++t2]=a2;

		if(i%t==0) printf("%d ",top);
	}

	putchar('\n');
	for(int i=h;i<=t0;++i)ans.push(now[i]);
    for(int i=h1;i<=t1;++i)ans.push(cut1[i]);
    for(int i=h2;i<=t2;++i)ans.push(cut2[i]);

    for(int i=1;ans.size();++i){
        if(i%t==0)printf("%d ",ans.top()+sigma);
        ans.pop();
    }

    return 0;
} 

257

我要做远方忠诚的儿子和物质的短暂情人……

    原文作者:杨辉三角问题
    原文地址: https://blog.csdn.net/syh8501/article/details/87901402
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞