zoukankan      html  css  js  c++  java
  • 算法竞赛入门经典 写题笔记(第一章 算法设计基础)

    可是我为什么要专门开一发写这个呢......

    1.1 思维的体操

    例题1 The Dragon of Loowater

    贪心

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m;
    int x[20005],y[20005];
    int main()
    {
    
        while(~scanf("%d %d",&n,&m)&&(n||m))
    	{
            for(int i=0;i<n;i++) scanf("%d",&x[i]);
            for(int i=0;i<m;i++) scanf("%d",&y[i]);
            sort(x,x+n);
            sort(y,y+m);
            int k=0;
            int num=0;
            for(int i=0;i<m;i++)
    		{
                if(x[k]<=y[i])
    			{
                    num+=y[i];
                    k++;
                    if(k==n) break;
                }
            }
            if(k<n) printf("Loowater is doomed!
    ");
            else printf("%d
    ",num);
        }
        return 0;
    }
    

    例题2 Commando War

    贪心

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,cnt;
    struct Node{int a,b;}node[MAXN];
    inline bool cmp(struct Node x,struct Node y){return x.b>y.b;}
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d",&n)!=EOF)
        {
            if(n==0) break;
            for(int i=1;i<=n;i++)
                scanf("%d%d",&node[i].a,&node[i].b);
            sort(&node[1],&node[n+1],cmp);
            long long ans=0,sum=0;
            for(int i=1;i<=n;i++)
            {
                sum+=node[i].a;
                ans=max(ans,sum+node[i].b);
            }
            cnt++;
            printf("Case %d: %lld
    ",cnt,ans);
        }
        return 0;
    }
    
    

    例题3 Spreading the Wealth(中位数,贪心)

    题目模型:给定数轴上的n个点,在数轴上的所有点中,中位数离所有的顶点距离之和最小。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 1000010
    using namespace std;
    int n;
    long long a[MAXN],c[MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
            long long tot=0;
            for(int i=1;i<=n;i++) tot+=a[i];
            long long M=tot/n;
            c[0]=0;
            for(int i=1;i<n;i++) c[i]=c[i-1]+a[i]-M;
            sort(&c[0],&c[n]);
            long long cur=c[n/2];
            long long ans=0;
            for(int i=0;i<n;i++) ans+=abs(cur-c[i]);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    

    例题4 Graveyard

    坐标的放缩法qwq

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 1000010
    using namespace std;
    int n,m;
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d%d",&n,&m)==2)
        {
            double ans=0.0;
            for(int i=1;i<=n;i++)
            {
                double pos=(double)(i*1.0/n)*(n+m);
                ans+=fabs(pos-1.0*floor(pos+0.5))/(n+m);
            }
            printf("%.4lf
    ",ans*10000);
        }
        return 0;
    }
    

    例题5 Piotr's Ants

    比较神奇的是要看出来这道题里面隐藏的性质:
    1、蚂蚁掉头的时候相当于对穿而过。比如说一个位置为1,方向为右的,两秒之后一定会有一个蚂蚁在位置为3上,方向为右,但是不一定是这只蚂蚁。
    2、因为碰撞会掉头,所以蚂蚁开始和结束的相对位置不变。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #define MAXN 100010
    using namespace std;
    int T,l,t,n,cnt;
    int Pos[MAXN];
    char s[10];
    struct Node{int pos,op,id;}node[MAXN],en[MAXN];
    inline bool cmp(struct Node x,struct Node y){return x.pos<y.pos;}
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d%d",&l,&t,&n);
    		cnt++;
    		for(int i=1;i<=n;i++) 
    		{
    			scanf("%d",&node[i].pos);
    			scanf("%s",s);
    			if(s[0]=='R') node[i].op=1;
    			else node[i].op=-1;
    			node[i].id=i;
    			en[i].pos=node[i].pos+node[i].op*t;
    			en[i].id=i;
    			en[i].op=node[i].op;
    		}
    //		for(int i=1;i<=n;i++) printf("i=%d %d %d
    ",i,node[i].pos,node[i].op);
    		sort(&node[1],&node[n+1],cmp);
    		for(int i=1;i<=n;i++) Pos[node[i].id]=i;
    		sort(&en[1],&en[n+1],cmp);
    		for(int i=1;i<n;i++)
    		{
    			if(en[i].pos==en[i+1].pos) en[i].op=en[i+1].op=0;
    		}
    		printf("Case #%d:
    ",cnt);
    		for(int i=1;i<=n;i++)
    		{
    			int cur=Pos[i];
    			if(en[cur].pos<0||en[cur].pos>l) printf("Fell off
    ");
    			else 
    			{
    				printf("%d ",en[cur].pos);
    				if(en[cur].op==-1) printf("L
    ");
    				else if(en[cur].op==0) printf("Turning
    ");
    				else printf("R
    ");
    			}
    		}
    		printf("
    ");
    	}
    	return 0;
    }
    

    例题6 Image Is Everything

    例题7 Even Parity

    枚举状态的化简
    虽然我们不能枚举所有可能的情况,但是我们可以找到依赖关系,通过已知条件确定未知的方法来减少枚举的数量。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 50
    using namespace std;
    int T,n,cnt;
    int a[MAXN][MAXN],cur[MAXN][MAXN];
    inline int solve(int x,int y)
    {
        int sum=0;
        if(x-2>=1) sum+=cur[x-2][y];
        if(y-1>=1) sum+=cur[x-1][y-1];
        if(y+1<=n) sum+=cur[x-1][y+1];
        return sum;
    }
    inline void print()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                printf("%d ",cur[i][j]|a[i][j]);
            printf("
    ");
        }
        printf("
    ");
    }
    inline int calc(int x)
    {
        for(int i=0;i<n;i++)
        {
            if(x&(1<<i)) cur[1][i+1]=1;
            else if(a[1][i+1]==1) return 0x3f3f3f3f;
        }
        for(int i=2;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(solve(i,j)&1) cur[i][j]=1;
                else 
                {
                    if(a[i][j]==1) return 0x3f3f3f3f;
                    else cur[i][j]=0;
                }
            }
        int cur_ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[i][j]==0&&cur[i][j]==1)
                    cur_ans++;
        // print();
        // printf("cur_ans=%d
    ",cur_ans);
        return cur_ans;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            cnt++;
            int jian=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    scanf("%d",&a[i][j]);
            int cur_ans=0x3f3f3f3f;
            for(int i=0;i<(1<<n);i++) memset(cur,0,sizeof(cur)),cur_ans=min(cur_ans,calc(i));
            if(cur_ans==0x3f3f3f3f) printf("Case %d: %d
    ",cnt,-1);
            else printf("Case %d: %d
    ",cnt,cur_ans);
        }
        return 0;
    }
    

    例题8 Colored Cubes

    例题9 Chinese Mahjong

    例题10 Help is needed for Dexter

    给定正整数n,你的任务是用最少的操作次数把序列1,2,3...,n中的所有数都变成0,每次操作可以从序列中选择一个或者多个证书,同时减去一个相同的正整数。
    f(n)=f(n/2)+1

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n;
    inline int solve(int x)
    {
        if(x==1) return 1;
        else return solve(x/2)+1;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d",&n)!=EOF)
            printf("%d
    ",solve(n));
        return 0;
    }
    
    

    例题11 A Different Task

    例题12 Assemble

    二分+贪心

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<ctime>
    #include<vector>
    #define MAXN 1010
    using namespace std;
    int T,n,m,cnt,ans;
    struct Node{string fa,name;int price,value;}node[MAXN<<1];
    struct Node2{int price,value;};
    map<string,int>id;
    vector<Node2>vec[MAXN];
    inline bool check(int x)
    {
    	int cur_ans=0;
    	for(int i=1;i<=cnt;i++)
    	{
    		int minn=2147483647;
    		for(int j=0;j<vec[i].size();j++)
    		{
    			if(vec[i][j].value<x) continue;
    			minn=min(minn,vec[i][j].price);
    		}
    		if(minn==2147483647) return false;
    		cur_ans+=minn;
    		if(cur_ans>m) return false;
    		
    	}
    	return true;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            cnt=0;
            id.clear();
            for(int i=1;i<=n;i++) vec[i].clear();
            for(int i=1;i<=n;i++)
            {
                cin>>node[i].fa>>node[i].name;
                scanf("%d%d",&node[i].price,&node[i].value);
                if(!id.count(node[i].fa)) id[node[i].fa]=++cnt;
                vec[id[node[i].fa]].push_back((Node2){node[i].price,node[i].value});
            }
            int l=0,r=(int)1e9+1;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if(check(mid)==true) ans=mid,l=mid+1;
                else r=mid-1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    例题13 Pie

    虽然不是“最小值最大”诸如此类的问题,但是采取二分答案的方法可以使得问题转化为判定性问题
    double类型的二分,注意eps比要求的精度多个2位就可以了,太多的话,二分会T

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define eps 1e-5
    #define pi acos(-1.0)
    #define MAXN 100010
    using namespace std;
    int n,f,T;
    double l=0.0,r;
    double R[MAXN];
    inline bool check(double x)
    {
    	int cur_ans=0;
    	for(int i=1;i<=n;i++)
    	{
    		double s=pi*R[i]*R[i];
    		cur_ans+=floor(s/x);
    	}
    	if(cur_ans>=f) return true;
    	else return false;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&f);
    		l=r=0.0;
    		for(int i=1;i<=n;i++)
    		{
    			int cur;
    			scanf("%d",&cur);
    			R[i]=1.0*cur;
    			r=max(r,R[i]*R[i]*pi);
    		}
    		f++;
    		while(l+eps<r)
    		{
    			double mid=(l+r)/2;
    			if(check(mid)==true) l=mid;
    			else r=mid;
    		}
    		printf("%.4lf
    ",l);
    	}
    	return 0;
    }
    

    例题14 Fill the Square

    贪心

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define MAXN 110
    using namespace std;
    int T,n,m,cnt;
    char a[MAXN][MAXN],s[MAXN];
    inline void solve(int x,int y)
    {
    	for(char ch='A';ch<='Z';ch++)
    	{
    		bool flag=true;
    		if(x>1&&a[x-1][y]==ch) flag=false;
    		if(x<n&&a[x+1][y]==ch) flag=false;
    		if(y>1&&a[x][y-1]==ch) flag=false;
    		if(y<n&&a[x][y+1]==ch) flag=false;
    		if(flag==true){a[x][y]=ch;break;}
    	}
    }
    int main()
    {
    
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d",&n);
    		cnt++;
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    				cin>>a[i][j];
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    				if(a[i][j]=='.')
    					solve(i,j);
    		printf("Case %d:
    ",cnt);
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=n;j++)
    				printf("%c",a[i][j]);
    			printf("
    ");
    		}
    	}
    	return 0;
    }
    

    例题15 Network

    在一个无根树上设定最少的关键点,使得树上每个点到关键点的距离都不超过K。
    无根树转有根树,然后从叶子节点开始,每次贪心地设定当前深度最大的叶子节点的K级祖先为关键节点。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define MAXN 100010
    using namespace std;
    int T,n,m,s,t,ans,k;
    int head[MAXN<<1],done[MAXN];
    vector<int>d[MAXN];
    struct Edge{int nxt,to;}edge[MAXN<<1];
    struct Node{int fa,dep;}node[MAXN];
    inline void add(int from,int to){edge[++t].nxt=head[from],edge[t].to=to,head[from]=t;}
    inline void dfs1(int x,int pre)
    {
    	node[x].fa=pre;
    	node[x].dep=node[pre].dep+1;
    	bool flag=false;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(v==pre) continue;
    		flag=true;
    		dfs1(v,x);
    	}
    	if(flag==false) d[node[x].dep].push_back(x);
    }
    inline void dfs2(int x,int pre,int cnt)
    {
    	if(cnt>k) return;
    	done[x]=1;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(v==pre) continue;
    		dfs2(v,x,cnt+1);
    	}
    }
    inline void solve()
    {
    	for(int i=n;i>k+1;i--)
    	{
    		if(d[i].size()==0) continue;
    		for(int j=0;j<d[i].size();j++)
    		{
    			int x=d[i][j];
    			if(done[x]) continue;
    			int v=x;
    			for(int tot=1;tot<=k;tot++) v=node[v].fa;
    //			printf("x=%d v=%d
    ",x,v);
    			dfs2(v,0,0);
    			ans++;
    		}
    	}
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d%d",&n,&s,&k);
    		memset(head,0,sizeof(head));
    		memset(edge,0,sizeof(edge));
    		memset(done,0,sizeof(done));
    		t=ans=0;
    		for(int i=1;i<=n;i++) d[i].clear();
    		for(int i=1;i<n;i++)
    		{
    			int u,v;
    			scanf("%d%d",&u,&v);
    			add(u,v),add(v,u);
    		}
    		dfs1(s,0);
    		solve();
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    例题16 Beijing Guards

    思路比较巧妙的一个题,我们考虑奇数情况的时候显然就是编号为奇数的人尽可能向前取,编号为偶数的人尽可能往后取。
    但是偶数的时候因为环的存在,我们需要考虑每个人执行上述贪心策略,是否可行。
    所以我们用二分来把这个最优化问题,转化为判定性问题。
    记录每个人在([1,a1])的范围内取了几个,在([a1+1,n])范围内取了几个(分别用(ll[i],rr[i])来表示),最后判断第n个人在([1,r1])里面是否取出数即可,如果有取出,那么就扩大l。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int T,n;
    int a[MAXN],ll[MAXN],rr[MAXN];
    inline bool check(int limit)
    {
    	int x=a[1],y=limit-a[1];
    	ll[1]=x,rr[1]=0;
    	for(int i=2;i<=n;i++)
    	{
    		if(i%2==1)
    		{
    			rr[i]=min(y-rr[i-1],a[i]);
    			ll[i]=a[i]-rr[i];
    		}
    		else
    		{
    			ll[i]=min(x-ll[i-1],a[i]);
    			rr[i]=a[i]-ll[i];
    		}
    	}
    	if(ll[n]==0) return true;
    	else return false;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	while(scanf("%d",&n)!=EOF)
    	{
    		if(n==0) break;
    		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    		if(n==1){printf("%d
    ",a[1]);continue;}
    		a[n+1]=a[1];
    		int l=0,r=0;
    		for(int i=1;i<=n;i++) l=max(l,a[i]+a[i+1]);
    		if(n%2==0) printf("%d
    ",l);
    		else
    		{
    			for(int i=1;i<=n;i++) r=max(r,a[i]*3);
    			while(l<r)
    			{
    				int mid=(l+r)>>1;
    				if(check(mid)) r=mid;
    				else l=mid+1;
    			}
    			printf("%d
    ",l);
    		}
    	}
    	return 0;
    }
    

    例题17 Age sort

    桶排

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 110
    using namespace std;
    int n;
    int cnt[MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d",&n)!=EOF)
        {
            if(n==0) break;
            memset(cnt,0,sizeof(cnt));
            int cur;
            for(int i=1;i<=n;i++) scanf("%d",&cur),cnt[cur]++;
            bool flag=false;
            for(int i=1;i<=100;i++)
            {
                if(cnt[i]==0) continue;
                for(int j=1;j<=cnt[i];j++)
                {
                    if(flag==true) printf(" ");
                    printf("%d",i);
                    flag=true;
                }
            }
            printf("
    ");
        }
        return 0;
    } 
    

    例题18 Open Credit System

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,T;
    int a[MAXN];
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d",&n);
    		int ans=-2147483647;
    		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    		int maxx=-2147483647;
    		for(int i=1;i<=n;i++)
    		{
    			if(i!=1) ans=max(ans,maxx-a[i]);
    			maxx=max(maxx,a[i]);
    			// printf("maxx=%d ans=%d
    ",maxx,ans);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    例题19 Calculator Conundrum

    Floyd判圈算法。用来处理带循环节的相关问题,可以在线性的时间内判定是否有环,如果选择1和2为前进步数的话,还可以算出环上的每一个元素。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,k,ans,T;
    int s[MAXN];
    inline int calc(int x)
    {
    	long long cur_ans=1ll*x*x;
    	int cnt=0;
    	while(cur_ans)
    	{
    		s[++cnt]=cur_ans%10;
    		cur_ans/=10;
    	}
    	cur_ans=0;
    	for(int i=cnt,j=1;i>=0&&j<=n;j++,i--)
    		cur_ans=cur_ans*10+s[i];
    	return cur_ans;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&k);
    		ans=k;
    		int k1=k,k2=k;
    		do
    		{
    			k1=calc(k1);
    			k2=calc(k2);
    			if(k2>ans) ans=k2;
    			k2=calc(k2);
    			if(k2>ans) ans=k2; 
    		}while(k1!=k2);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    例题20 Metor

    一维扫描线维护信息
    (但是蓝书上写的预处理l,r区间的方法真的是好qwq)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #define MAXN 200010
    using namespace std;
    
    struct lin{
        double x;
        int type;
        bool operator<(const lin &a) const{
            return x<a.x||(x==a.x&&type>a.type);
        }
    }line[MAXN];
    
    void updat(int x,int a,int w,double &l,double &r)
    {
        if(!a){
            if(x<=0||x>=w)
                r=l-1;
        }
        else
            if(a>0){
                l=max(l,-(double)x/a);
                r=min(r,(double)(w-x)/a);
            }
            else{
                l=max(l,(double)(w-x)/a);
                r=min(r,-(double)x/a);
            }
    }
    
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
        int t;
        scanf("%d",&t);
        while(t--){
            int w,h,n,e=0; 
            scanf("%d%d%d",&w,&h,&n);
            for(int i=0;i<n;i++){
                int x,y,a,b;
                scanf("%d%d%d%d",&x,&y,&a,&b);
                double l=0,r=1e9;
                updat(x,a,w,l,r);
                updat(y,b,h,l,r);
                if(r>l){ 
                    line[e]=(lin){l,0},e++;
                    line[e]=(lin){r,1},e++;
                }
            }
            sort(line,line+e);
            int cnt=0,ans=0;
            for(int i=0;i<e;i++){ 
                if(line[i].type==0){
                    cnt++; 
                    ans=max(ans,cnt); 
                }
                else cnt--; 
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    例题21 Subsequence

    (O(n^2))化简到O(n)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,s;
    int a[MAXN];
    int main()
    {
    	while(scanf("%d%d",&n,&s)==2)
    	{
    		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    		int l=1,r=0,ans=0,minn=2147483647;
    		for(int i=1;i<=n;i++)
    		{
    			ans+=a[i];r++;
    			if(ans>=s)
    			{
    				while(ans-a[l]>=s&&l<r) ans-=a[l],l++;
    				minn=min(minn,r-l+1);
    			}
    		}
    		if(minn==2147483647) printf("0
    ");
    		else printf("%d
    ",minn);
    	}
    	return 0;
    }
    

    例题22 City Games

    请注意这个题的矩阵中其实有空格。。。
    悬线法模板

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define MAXN 1010
    using namespace std;
    int T,n,m,ans;
    int up[MAXN][MAXN],r[MAXN][MAXN],l[MAXN][MAXN];
    char a[MAXN][MAXN],s[MAXN];
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&m);
    		ans=0;
    		for(int i=1;i<=n;++i)
                for(int j=0;j<m;++j)
    			{
                    int ch=getchar();
                    while(ch!='F'&&ch!='R') ch=getchar();
                    a[i][j+1]=ch;
                }
    		for(int i=1;i<=n;i++)
    		{
    			int ll=0,rr=m+1;
    			for(int j=1;j<=m;j++)
    			{
    				if(a[i][j]!='F') {up[i][j]=l[i][j]=0;ll=j;}
    				else           
    				{
    					up[i][j]=(i==1)?1:up[i-1][j]+1;
    					l[i][j]=(i==1)?ll+1:max(l[i-1][j],ll+1);
    				}
    			}
    			for(int j=m;j>=1;j--)
    			{
    				if(a[i][j]!='F'){r[i][j]=m+1;rr=j;}
    				else
    				{
    					r[i][j]=(i==1)?rr-1:min(r[i-1][j],rr-1);
    					ans=max(ans,up[i][j]*(r[i][j]-l[i][j]+1));
    				}
    			}
    		}
    		printf("%d
    ",ans*3);
    	}
    	return 0;
    }
    

    例题23 Distant Galaxy

    部分枚举 可以有效地降低复杂度qwq
    运用了子序列这道例题里面提到的将枚举两个端点化简到(O(n))复杂度的求最值问题的小技巧

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,cnt,sum,ans;
    struct Node{int x,y;}node[MAXN];
    int y[MAXN],le[MAXN],up1[MAXN],up2[MAXN];
    inline bool cmp(struct Node x,struct Node y){return x.x<y.x;}
    inline int solve()
    {
    	sort(&node[1],&node[n+1],cmp);
    	sort(&y[1],&y[n+1]);
    	int tot=unique(&y[1],&y[n+1])-y-1;
    	if(tot<=2) return n;
    	int cur_ans=0;
    	for(int i=1;i<=tot;i++)
    	{
    		for(int j=i+1;j<=tot;j++)
    		{
    			int y_down=y[i],y_up=y[j];
    			sum=0;
    			for(int k=1;k<=n;k++)
    			{
    				if(k==1||node[k].x!=node[k-1].x)
    				{
    					sum++;
    					up1[sum]=up2[sum]=0;
    					le[sum]=le[sum-1]+up2[sum-1]-up1[sum-1];
    				}
    				if(node[k].y>y_down&&node[k].y<y_up) up1[sum]++;
    				if(node[k].y>=y_down&&node[k].y<=y_up) up2[sum]++;
    			}
    			if(sum<=2) return n;
    			int maxx=0;
    			for(int k=1;k<=sum;k++)
    			{
    				ans=max(ans,le[k]+up2[k]+maxx);
    				maxx=max(maxx,up1[k]-le[k]);
    			}
    		}
    	} 
    	return ans;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	while(scanf("%d",&n)==1)
    	{
    		if(n==0) break;
    		for(int i=1;i<=n;i++) scanf("%d%d",&node[i].x,&node[i].y),y[i]=node[i].y;
    		ans=0;
    		cnt++;
    		printf("Case %d: %d
    ",cnt,solve());
    	}
    	return 0;
    }
    

    例题24 Garbage Heap

    (O(n^5))计算最大子立方体(不一定非要是正方体qwq)
    一维枚举套二维前缀和qwq

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define INF 0x3f3f3f3f3f3f3f3f
    #define MAXN 25
    using namespace std;
    int a,b,c,T;
    long long ans;
    long long val[MAXN][MAXN][MAXN],sum[MAXN][MAXN][MAXN][MAXN],pre_max[MAXN][MAXN][MAXN][MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&a,&b,&c);
            for(int i=1;i<=a;i++)
                for(int j=1;j<=b;j++)
                    for(int k=1;k<=c;k++)
                        scanf("%lld",&val[i][j][k]);
    	memset(sum,0,sizeof(sum));
    	memset(pre_max,0,sizeof(pre_max));
            ans=-INF;
            for(int k=1;k<=a;k++)
            {
                for(int i=1;i<=b;i++)
                {
                    for(int j=i;j<=b;j++)
                    {
                        for(int p=1;p<=c;p++)
                        {
                            long long cur_ans=0;
                            for(int q=p;q<=c;q++)
                            {
                                cur_ans+=val[k][j][q];
                                sum[i][j][p][q]=sum[i][j-1][p][q]+cur_ans;
                                if(k==1) pre_max[i][j][p][q]=sum[i][j][p][q];
                                else pre_max[i][j][p][q]=max(pre_max[i][j][p][q]+sum[i][j][p][q],sum[i][j][p][q]);
                                ans=max(ans,pre_max[i][j][p][q]);
                            }
                        }
                    }
                }
            }
            printf("%lld
    ",ans);
            if(T) printf("
    ");
        }
        return 0;
    }
    

    例题25 Jurassic Remains

    折半枚举

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #define MAXN 100010
    using namespace std;
    int n,ans;
    int sum[MAXN];
    char s[MAXN];
    map<int,int>ex;
    inline int bitcount(int x){return x==0?0:bitcount(x/2)+(x&1);}
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d",&n)!=EOF)
        {
            ex.clear();
            for(int i=1;i<=n;i++)
            {
                scanf("%s",s);
                sum[i]=0;
                for(int j=0,len=strlen(s);j<len;j++) sum[i]^=(1<<(s[j]-'A'));
            }
            for(int i=0;i<(1<<(n/2));i++)
            {
                int cur_ans=0;
                for(int j=0;j<(n/2);j++)
                {
                    if(i&(1<<j))
                        cur_ans^=sum[j+1];
                }
                if(!ex.count(cur_ans)||bitcount(ex[cur_ans])<bitcount(i)) ex[cur_ans]=i;
            }
            int n1=n/2,n2=n-n1;
            ans=0;
            for(int i=0;i<(1<<(n2));i++)
            {
                int cur_ans=0;
                for(int j=0;j<(n2);j++)
                {
                    if(i&(1<<j))
                        cur_ans^=sum[n1+j+1];
                }
                if(ex.count(cur_ans)&&bitcount(ans)<bitcount(ex[cur_ans])+bitcount(i)) 
                    ans=(i<<n1)^ex[cur_ans];
                    // ans=(ex[cur_ans]<<n1)^i;
            }
            printf("%d
    ",bitcount(ans));
            for(int i=0;i<n;i++) 
                if(ans&(1<<i))
                    printf("%d ",i+1);
            printf("
    ");
        }
        return 0;
    }
    

    例题26 And Then There Was One

    普通的约瑟夫问题,递推公式是(dp[i]=(dp[i-1]+k)%i)(注意,这个版本是从0开始编号的,如果求的是从1开始编号,那么应该最后答案是dp[n]+1)
    第一个删除m,那意味着从(m-k)开始,所以最终答案是((m-k+1+f[n])%n)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int T,n,m,k;
    int dp[MAXN];
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	while(scanf("%d%d%d",&n,&k,&m)==3)
    	{
    		if(n==0) break;
    		dp[1]=0;
    		for(int i=2;i<=n;i++) dp[i]=(dp[i-1]+k)%i;
    		int ans=(m-k+1+dp[n])%n;
    		while(ans<=0) ans+=n;
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    例题27 Prince ans Princess

    如何在(O(nlogn))的时间内算出A和B的最长公共子序列?
    正解是将B转换成其数值在A中出现的位置,比如说A 1 5 2 4 3,B 5 4 2 1 3,B转换成2 4 3 1 5.
    然后求最长上升子序列长度即可qwq

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int T,n,p,q,ans,tot;
    int num[MAXN],b[MAXN],dp[MAXN];
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		ans=0;
    		tot++;
    		scanf("%d%d%d",&n,&p,&q);
    		memset(num,0,sizeof(num));
    		for(int i=1;i<=p+1;i++)
    		{
    			int cur;
    			scanf("%d",&cur);
    			num[cur]=i;
    		}
    		n=0;
    		for(int i=1;i<=q+1;i++)
    		{
    			int cur;
    			scanf("%d",&cur);
    			if(num[cur]) b[++n]=num[cur];
    		}
    		int cnt=0;
    		dp[0]=-1;
    		for(int i=1;i<=n;i++)
    		{
    			if(b[i]>dp[cnt]) dp[++cnt]=b[i];
    			else
    			{
    				int pos=lower_bound(&dp[1],&dp[cnt+1],b[i])-dp;
    				dp[pos]=b[i];
    			}
    		}
    		printf("Case %d: %d
    ",tot,cnt);
    	}
    	return 0;
    }
    

    例题28 Game of Sum

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 1010
    using namespace std;
    int n;
    int a[MAXN],g[MAXN][MAXN],f[MAXN][MAXN],d[MAXN][MAXN],sum[MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d",&n)==1)
        {
            if(!n) break;
            sum[0]=0;
            for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
            for(int i=1;i<=n;i++) g[i][i]=d[i][i]=f[i][i]=a[i];
            for(int l=1;l<n;l++)   
                for(int i=1;i+l<=n;i++)
                {
                    int j=i+l;
                    int cur_ans=0;
                    cur_ans=min(cur_ans,f[i+1][j]);
                    cur_ans=min(cur_ans,g[i][j-1]);
                    d[i][j]=sum[j]-sum[i-1]-cur_ans;
                    f[i][j]=min(d[i][j],f[i+1][j]);
                    g[i][j]=min(d[i][j],g[i][j-1]);
                }
            printf("%d
    ",2*d[1][n]-sum[n]);
        }
        return 0;
    }
    

    例题29 Hacker's Crackdown

    状压DP

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 17
    using namespace std;
    int n,cnt;
    int con[1<<MAXN],cover[1<<MAXN],dp[1<<MAXN];
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	while(scanf("%d",&n)==1)
    	{
    		if(n==0) break;
    		cnt++;
    		for(int i=1;i<=n;i++)
    		{
    			int k,cur;
    			scanf("%d",&k);
    			con[i]=(1<<(i-1));
    			while(k--) scanf("%d",&cur),con[i]|=(1<<cur);
    		}
    		memset(cover,0,sizeof(cover));
    		for(int i=0;i<(1<<n);i++)
    		{
    			for(int j=0;j<n;j++)
    				if(i&(1<<j))
    					cover[i]|=con[j+1];
    		}
    		memset(dp,0,sizeof(dp));
    		for(int i=0;i<(1<<n);i++)
    		{
    			for(int s0=i;s0;s0=(s0-1)&i)
    			{
    				if(cover[s0]==(1<<n)-1)
    					dp[i]=max(dp[i],dp[i^s0]+1);
    			}
    		}
    		printf("Case %d: %d
    ",cnt,dp[(1<<n)-1]);
    	}
    	return 0;
    }
    
    

    例题30 Placing Lampposts

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int T,n,m,t;
    int head[MAXN<<1],dp[MAXN][2],sum[MAXN][2],done[MAXN];
    struct Edge{int nxt,to;}edge[MAXN<<1];
    inline void add(int from,int to){edge[++t].nxt=head[from],edge[t].to=to,head[from]=t;}
    inline void dfs(int x,int pre)
    {
    	dp[x][1]=1;
    	dp[x][0]=0;
    	done[x]=1;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(v==pre) continue;
    		dfs(v,x);
    		// printf("x=%d v=%d
    ",x,v);
    		dp[x][0]+=dp[v][1];
    		sum[x][0]+=sum[v][1];
    		if(dp[v][1]<dp[v][0])
    		{
    		    dp[x][1]+=dp[v][1];
    			sum[x][1]+=sum[v][1]+1;
    		}
    		else if(dp[v][0]<dp[v][1])
    		{
    			dp[x][1]+=dp[v][0];
    			sum[x][1]+=sum[v][0];
    		}
    		else
    		{
    			dp[x][1]+=dp[v][1];
    			sum[x][1]+=max(sum[v][1]+1,sum[v][0]);
    		}
    	}
    	// printf("dp[%d][0]=%d dp[%d][1]=%d
    ",x,dp[x][0],x,dp[x][1]);
    	// printf("sum[%d][0]=%d sum[%d][1]=%d
    ",x,sum[x][0],x,sum[x][1]);
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T--)
    	{
    		t=0;
    		memset(head,0,sizeof(head));                   
    		memset(edge,0,sizeof(edge));
    		memset(done,0,sizeof(done));
    		memset(sum,0,sizeof(sum));
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    		{
    			int u,v;
    			scanf("%d%d",&u,&v);
    			add(u,v),add(v,u);
    		}
    		int ans1=0,ans2=0;
    		for(int i=0;i<n;i++)
    		{
    			if(done[i]==1) continue;
    			dfs(i,-1);
    			if(dp[i][0]>dp[i][1])
    			{
    				ans1+=dp[i][1];
    				ans2+=sum[i][1];
    			}
    		    else if(dp[i][0]<dp[i][1])
    			{
    				ans1+=dp[i][0];
    				ans2+=sum[i][0];
    			}
    		    else
    			{
    				ans1+=dp[i][1];
    				ans2+=max(sum[i][1],sum[i][0]);
    			}
    		}
    			printf("%d %d %d
    ",ans1,ans2,m-ans2);
    	}
    	return 0;
    }
    
    

    例题31 Robotruck

    例题32 Sharing Chocolate

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define MAXN 110
    #define LOG 16
    using namespace std;
    int n,X,Y,tim;
    int a[MAXN],dp[MAXN][1<<LOG],done[MAXN][1<<LOG],sum[1<<LOG];
    inline int calc(int x){return x==0?0:calc(x/2)+(x&1);}
    inline int search(int x,int s)
    {
    	if(done[x][s]) return dp[x][s];
    	done[x][s]=1;
    	if(calc(s)==1) 
    	{
    		dp[x][s]=1;
    		return 1;
    	}
    	for(int s1=(s-1)&s;s1;s1=(s1-1)&s)
    	{
    		int s2=s-s1;
    		if(sum[s1]%x==0&&search(min(x,sum[s1]/x),s1)&&search(min(x,sum[s2]/x),s2))
    		{
    			dp[x][s]=1;
    			return 1;
    		}
    		int y=sum[s]/x;
    		if(sum[s1]%y==0&&search(min(y,sum[s1]/y),s1)&&search(min(sum[s2]/y,y),s2)) 
    		{
    			dp[x][s]=1;
    			return 1;
    		}
    	}
    	dp[x][s]=0;
    	return 0;
    }
    int main()
    {
    	while(scanf("%d",&n)==1)
    	{
    		if(n==0) break;
    		++tim;
    		memset(done,0,sizeof(done));
    		memset(sum,0,sizeof(sum));
    		memset(dp,0,sizeof(dp));
    		int maxx=(1<<n)-1,tot=0;
    		scanf("%d%d",&X,&Y);
    		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    		for(int i=0;i<=maxx;i++)
    			for(int j=0;j<n;j++)
    				if(i&(1<<j))
    					sum[i]+=a[j+1];
    		int ans=0;
    		if(sum[maxx]!=X*Y||sum[maxx]%X!=0) ans=0;
    		else ans=search(min(X,Y),maxx);
    		printf("Case %d: %s
    ",tim,ans==0?"No":"Yes");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android Studio不自动代码提示问题解决
    公司邮箱
    IntentService2
    python帮助信息和常见强制转换
    列表,字典的常用方法
    python的类型(一)
    python运算符
    pycharm调试技巧
    python开发工具
    python安装
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10681071.html
Copyright © 2011-2022 走看看