• Educational Codeforces Round 26 [ D. Round Subset ] [ E. Vasya's Function ] [ F. Prefix Sums ]


    PROBLEM D - Round Subset

      OvO http://codeforces.com/contest/837/problem/D

      837D

      DP,

      dp[i][j]代表已经选择了i个元素,当2的个数为j的时候5的个数的最大值

      得注意最大值(貌似因为这个喵呜了一大片喵~☆)

     

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int M=64*202;
    const int N=M-2;
    
    int n,k;
    int f[222][M];	//f[i][j] used num=i, sum of k2=j, val of f[i][j] = max sum of k5
    int k2[222],k5[222];
    
    void init()
    {
    	memset(k2,0,sizeof(k2));
    	memset(k5,0,sizeof(k5));
    	memset(f,-1,sizeof(f));
    }
    
    int main()
    {
    	int i,j,t;
    	ll tmp;
    	cin>>n>>k;
    	init();
    	for(i=1;i<=n;i++)
    	{
    		scanf("%I64d",&tmp);
    		while(tmp%2==0)
    			tmp/=2,k2[i]++;
    		while(tmp%5==0)
    			tmp/=5,k5[i]++;
    	}
    	f[0][0]=0;
    	for(i=1;i<=n;i++)
    		for(j=k;j>=1;j--)
    			for(t=N;t>=k2[i];t--)
    				if(f[j-1][t-k2[i]]!=-1)
    					f[j][t]=max(f[j][t],f[j-1][t-k2[i]]+k5[i]);
    	int ans=0;
    	for(t=0;t<=N;t++)
    		ans=max(ans,min(t,f[k][t]));
    	cout<<ans<<endl;
    	return 0;
    }
     
    

     

    PROBLEM E - Round Subset

      OvO http://codeforces.com/contest/837/problem/E

      837E

      当B和A公约数不为1的时候(开始的时候,或者B减了一定次数1的时候),就相当于A和B同除以gcd(A,B),然后B继续一次减1。

      这样只要每次计算出每次B要减多少次1才能和A有不为1的公约数。

      那么预处理出A的质因数,然后每次对A的质因数判断一下,哪个最近(也就是模最小)即可。

    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    
    using namespace std;
    
    typedef long long ll;
    
    const ll M=1e6+44;
    const ll inf=1e18;
    
    ll A,B;
    ll prim[M];
    ll lp,nump[M];
    ll ans;
    
    void init(ll spl)
    {
    	ll i,j;
    	lp=0;
    	for(i=2;i*i<=spl;i++)
    		if(spl%i==0)
    		{
    			prim[++lp]=i;
    			nump[lp]=0;
    			while(spl%i==0)
    				spl/=i,nump[lp]++;
    		}
    	if(spl!=1)
    	{
    		prim[++lp]=spl;
    		nump[lp]=1;
    	}
    }
    
    void deal()
    {
    	if(B==0)
    		return ;
    	if(A==1)
    	{
    		ans+=B;
    		return ;
    	}
    	ll i,j,mn;
    	ll tmp,gcd;
    	mn=inf;
    	for(i=1;i<=lp;i++)
    	{
    		tmp=B%prim[i];
    		if(tmp<mn)
    			mn=tmp;
    	}
    	tmp=mn;
    	ans+=tmp;
    	B-=tmp;
    	gcd=__gcd(A,B);
    	A/=gcd; B/=gcd;
    	for(i=1;i<=lp;i++)
    		if(gcd%prim[i]==0)
    		{
    			while(gcd%prim[i]==0)
    				gcd/=prim[i],nump[i]--;
    			if(nump[i]==0)
    			{
    				swap(nump[i],nump[lp]);
    				swap(prim[i],prim[lp]);
    				lp--; i--;
    			}
    		}
    	deal();
    }
    
    void solve()
    {
    	ans=0;
    	deal();
    	printf("%I64d
    ",ans);
    }
    
    int main()
    {
    	scanf("%I64d%I64d",&A,&B);
    	init(A);
    	solve();
    	return 0;
    }
    

      

      

    PROBLEM F - Prefix Sums

      OvO http://codeforces.com/contest/837/problem/F

      837F

      由于新生成的m+1个数列第一个肯定为0,所以可以忽略掉,当作每次新生成的数列只拥有m个元素

      然后 举个栗子

      当s={1,0,0,0,0} 可以得到如下矩阵

      

      显然这拥有某神秘三角的性质

      然后二分答案,每次通过组合数来算就行了,由于太大直接退出,所以不会超时(如果C(p,q),p-q<q的话,转化为C(p,p-q))

      

    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cstdio>
    
    using namespace std;
    
    typedef long long ll;
    
    const ll M=2e5+44;
    
    ll n,k;
    ll sum;
    ll s[M];
    
    bool check(ll spl)
    {
    	ll i,j,t,x,y,p,q;
    	double sum=0,tmp;
    	for(t=0;t<n;t++)
    	{
    		if(s[t]==0) continue;
    		x=spl; y=(n-1)-t;	//s[i]*c(y+x-1,x-1)
    		p=x-1; q=x+y-1;		//c(q,p)
    		p=min(q-p,p);
    		tmp=s[t];
    		for(i=q,j=p;j>=1;j--,i--)
    		{
    			tmp=tmp*i/j;
    			if(tmp>=k)
    				return true;
    		}
    		sum+=tmp;
    		if(sum>=k) return true;
    	}
    	return false;
    }
    
    void solve()
    {
    	ll li=0,ri=k,mid;
    	while(li<ri-1)
    	{
    //		cout<<li<<' '<<ri<<endl;
    		mid=(li+ri)>>1;
    		if(check(mid))
    			ri=mid;
    		else
    			li=mid;
    	}
    	cout<<ri<<endl;
    }
    
    int main()
    {
    	ll i,j,tmp;
    	cin>>n>>k;
    	for(i=0;i<n;i++)
    	{
    		scanf("%I64d",&s[i]);
    		if(s[i]>=k)
    		{
    			printf("0
    ");
    			return 0;
    		}
    	}
    	solve();
    	return 0;
    }
    

      

  • 相关阅读:
    判断二叉树是否是完全二叉树
    二叉搜索树的第k个节点
    二叉树的深度
    二叉搜索树与双向链表
    二叉搜索树的后序遍历序列
    poj 2192 (DP)
    poj 1159 (DP LCS)
    poj 1934(LCS)
    《编程之美》读书笔记 -- 1.2中国象棋问题
    poj 1050(DP)
  • 原文地址:https://www.cnblogs.com/FxxL/p/7282909.html
Copyright © 2020-2023  润新知