zoukankan      html  css  js  c++  java
  • 暑期集训7/14

    网址:https://vjudge.net/contest/170761#overview

    A题思路:

    B题思路:

    C题思路:

    题目要求:

    求最长连续子串,在相等大小下,长度要求最长,再起点最小。

    思路:

    因为ans都是大于等于零的,所以我们就当加到sum小于零时,就把sum归零,起点变成当前的i,继续。

    核心代码:

    int mx=a[1],sum=mx;
            int len=0;
            int x=1;
            int be=1,en=1;
            for(int i=2;i<n;i++)
            {
            	if(sum<0)
            	{
            		sum=0;
            		x=i;
    			}
    			sum+=a[i];  
                if(sum>mx||(sum==mx&&i-x>en-be))    
                {  
     				mx=sum;
     				be=x;
     				en=i;
                } 
            }    
    

     D题思路:

    E题思路:

    F题思路:

    G题思路:

    题目要求:

      在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
      这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
      1. CD 当前目录名...目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
      2. CD .. (返回当前目录的上级目录)
      现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?

    思路:预处理,每个节点的深度,然后求他们的最近祖先(判断条件顺序要正确,不然wa到你心态爆炸)

    代码:

    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <vector> 
    #include <map>
    using namespace std;
    const int maxn=100007;
    int fa[maxn];
    int f[maxn][30];
    int depth[maxn];
    vector<int> tree[maxn];
    map<string,int> mp;
    void init(int u,int p,int d)
    {
        f[u][0]=p,depth[u]=d;
        for(int i=1;i<=20;i++)
            f[u][i]=f[f[u][i-1]][i-1];
        int sz=tree[u].size();
        for(int i=0;i<sz;i++)
        {
            int v=tree[u][i];
            if(v!=p) init(v,u,d+1);
        }
    }
    int lca(int a,int b)
    {
        if(depth[a]<depth[b]) swap(a,b);
        for(int i=19,d=depth[a]-depth[b];i>=0;i--)
        {
            if(d>>i&1)
            {
                a=f[a][i];
            }
        }
        if(a==b) return a;
        for(int i=19;i>=0;--i)
            if(f[a][i]!=f[b][i])
                a=f[a][i],b=f[b][i];
        return f[a][0];
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n,m;
            memset(fa,0,sizeof(fa));
            mp.clear();
            int cnt=1;
            scanf("%d %d",&n,&m);
            for(int i=1;i<=n+5;i++) tree[i].clear();
            string a,b;
            for(int i=0;i<n-1;i++)
            {
                cin>>a>>b;
                //cout<<a<<"  "<<b<<endl;
            //    int f=mp[b],s=mp[a];
                if(mp[a]==0) mp[a]=cnt++;
                if(mp[b]==0) mp[b]=cnt++;
                //cout<<mp[a]<<"  "<<mp[b]<<endl;
                tree[mp[b]].push_back(mp[a]);
                fa[mp[a]]=1;
            } 
            //getchar();
            int root;
            for(int i=1;i<cnt;i++) if(fa[i]==0) root=i;
            init(root,root,0);
            for(int i=0;i<m;i++)
            {
                cin>>a>>b;
                //cout<<a<<"ttt"<<b<<endl; 
                int a1=mp[a],b1=mp[b];
                int ans;
                int samefather=lca(a1,b1);
                //cout<<samefather<<endl;
                if(samefather==b1) 
                {
                    ans=depth[a1]-depth[b1];
                }
                else if(samefather==a1) ans=1;
                else 
                {
                    ans=depth[a1]-depth[samefather]+1;
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }

    H题思路:

    题目要求: 求最多去掉M块石头的最短距离的最大值,其实就是去掉M块,因为你每去掉一块就会,使最短距离变大或者不变,所以去掉M就是最优的,然后弄个函数int f(int d)表示最短距离为d时候去掉的石头数目,然后我们二分d(0到L),看看在满足f(d)小于等于M的情况下的,最大d。

    核心代码:

    int f(int d)
    {
        ll now=0;
        int k=1;
        int t=m;
        while(t>=0&&k<=n+1)
        {
            if(now+d>a[k]) t--;//cout<<now<<"  "<<k<<endl;
            else now=a[k];
            k++;
            //if(k==n+1) break;
        }
        if(t>=0) return 1;
        else return 0;
    }
    
    if(n==m)
        {
            return 0*printf("%lld
    ",l);
        }
        ll l1=0,r1=l;
        ll d=l/2;
        while(l1+1<r1)
        {
        //cout<<d<<"  "<<f(d)<<endl;
            if(f(d)) l1=d;
            else  r1=d;
            d=(r1+l1)/2;
        }
        if(f(r1))
        printf("%lld
    ",r1);
        else printf("%lld
    ",l1);
    

     I题思路:

    题目要求:在m的时间内,把n个钱分成小于等于m个的组,使最大值最小

    思路:二分(maxi,sumi),求出符合情况的最小值

    核心代码:

    bool judge(ll mid)
    {
        ll sum=0,cnt=1;
        for(int i=1;i<=n;i++)
        {
            if(sum+a[i]<=mid)  //当前i天之和<=mid时,把他们归并到一组
                sum+=a[i];
            else               //若 前i-1天之和 加上第i天的花费 大于mid
            {
                sum=a[i];  //则把前i-1天作为一组,第i天作为下一组的第一天
                cnt++;    //此时划分的组数+1
            }
        }
        if(cnt>m)
        return false;
        else return true;
    }//判断当前金额是否符合
    ll l=mx,r=sum;
            ll md=(mx+sum)/2;
            while(l<r)
            {
            //cout<<md<<endl;
    
                if(!judge(md)) l=md+1;
                else r=md-1;
                md=(l+r)/2;
            }
            printf("%lld
    ",l);
    //二分,输出符合情况的最小值
    

     J题思路:

    直接看代码:

    #include <iostream>
    #include <stdio.h>
    #include <map>
    #include <cmath>
    #define ll long long
    using namespace std;
    const int maxn=100010;
    int st[25][maxn];
    int gcd(int a,int b)
    {
    	return b==0?a:gcd(b,a%b);
    }
    int a[maxn];
    int lg[maxn];
    int rgcd(int l,int r)
    {
    	int k = lg[r-l+1];
    	return gcd(st[k][l],st[k][r-(1<<k)+1]); //真的是脑残,把gcd写成max,然后找一个上午才找出这个错误,你是弱智吗,??????? 
    }
    int main()
    {
    	int T;
    	//cout<<gcd(4,12);
    	scanf("%d",&T);
    	int cnt=1;
    	lg[1]=0;
    	for(int i=2;i<maxn;i++) lg[i]=lg[i>>1]+1;
    	while(T--)
    	{
    		int n,m;
    		scanf("%d",&n);
    		// st,预处理任意区间的gcd 
    		for(int i=1;i<=n;i++) scanf("%d",a+i),st[0][i]=a[i];
    		for(int j=1;j<20;j++)
    		{
    			for(int i=1;i+(1<<j)<=n+1;i++)
    			{
    				st[j][i]=gcd(st[j-1][i],st[j-1][i+(1<<(j-1))]);
    			}
    		}
    		//核心:gcd性质,同一左端点,随着数列的变长 ,gcd递减(不是严格递减),所以他们可能出现(线1,点2,线3)这种的 线1gcd>点2gcd>线3gcd(在同一左端点的情况下),然后我们枚举左端点o(n) ::线表示有多个点 ,增加一个数字,gcd减少的话,至除以2 
    		map<int,ll> mp;
    		for(int i=1;i<=n;i++)
    		{
    			int gd=a[i];
    			int j=i;
    			while(j<=n)
    			{
    				int l=j,r=n;
    				
    				while(l+1<r)
    				{
    					int mid=(l+r)>>1;
    					//cout<<l<<"   "<<r<<endl;
    					if(rgcd(l,r)==gd) l=mid;
    					else r=mid;
    				} 
    				mp[gd]+=l-j+1,j=l+1;
    				//if(gd==9) cout<<j<<endl;
    				gd=gcd(gd,a[j]);
    			}
    		}
    		scanf("%d",&m);
    		printf("Case #%d:
    ",cnt);
    		for(int i=0;i<m;i++)
    		{
    			int l,r;
    			scanf("%d %d",&l,&r);
    			int ansgcd=rgcd(l,r);
    			cout<<ansgcd<<" "<<mp[ansgcd]<<endl;
    		}
    		cnt++;
    		mp.clear(); 
    	}
    	return 0;
    }
    

    K题思路:

    题目要求:求联通快的面积,输出先按最大面积,相同就按照字典序,用struct保存这个联通块的字符和面积(多=多组数据记得要重置struct)

    核心代码:

    int dfs(char ans,int x,int y)
    {
    	s[x][y]='.';
    	int cnt=1;
    	for(int i=0;i<=3;i++)
    	{
    		int nx=x+dx[i];
    		int ny=y+dy[i];
    		if(nx>=0&&nx<n&&ny>=0&&ny<m)
    		{
    			if(s[nx][ny]==ans) 
    			{
    				cnt+=dfs(ans,nx,ny);
    			}
    		}
    	}
    	return cnt;
    }
    //计算面积
    for(int i=1;i<c;i++) 
    		{
    			sa[i].m=0;
    			sa[i].ch='.';
    		}
    //重置struct
    

     L题思路:

    要求:求联通快的最大面积,K题的缩水版

    M题思路:

    题目要求判断一个大整数是否是11的倍数;

    方法一:(直接模拟)

    for(int i=0;i<len;i++)
            {
                ans=(s[i]-'0')+ans*10;
                ans%=11;
            }
            cout<<s;
            if(ans%11==0)
    

     方法二:

    一个十进制的数可以变成xn*10^n+......+x0*1,把每位都减去11就是xn*(-1)^n+...+x0*(-1)^0,

    那就变成看看奇数位和偶数位之茶能不能整除11.

    for(int i=0;i<len;i+=2)
                a+=(s[i]-'0');
            for(int i=1;i<len;i+=2)
                b+=(s[i]-'0');
            cout<<s;
            int x=abs(b-a);
            if(x%11==0)
    

     N题思路:

    题目要求:切一条直线,使得左右两边点的数目相同;

    思路:因为数据很小,直接暴力枚举即可

    for(i=-500;i<=500;i++)
            {
                for(j=-500;j<=500;j++)
                {
                    n1=0,n2=0;
                    if(i==0&&j==0) continue;
                    for(int k=1;k<=2*n;k++)
                    {
                        if((i*x[k]+j*y[k])>0) n1++;
                        if((i*x[k]+j*y[k])<0) n2++;
                        if((i*x[k]+j*y[k])==0) break;
                    }
                    if(n1==n2&&n1==n) break;
                }
                if(n1==n2&&n1==n) break;
            }
            cout<<i<<" "<<j<<endl;
    

     O题思路:

  • 相关阅读:
    JAVA 分布式
    Spring Boot -01- 快速入门篇(图文教程)
    MyBatis -01- 初识 MyBatis + MyBatis 环境搭建
    Vue 框架-12-Vue 项目的详细开发流程
    Vue 框架-11-介绍src文件流程及根组件app+HBuilder 配置
    Vue 框架-10-搭建脚手架 CLI
    LeetCode
    LeetCode
    LeetCode
    LeetCode
  • 原文地址:https://www.cnblogs.com/chinacwj/p/7172061.html
Copyright © 2011-2022 走看看