zoukankan      html  css  js  c++  java
  • 6.28日模拟考试总结(T1:翻转游戏;T2:抢掠计划,T3:测绘,T4:奖学金)

    今天的考试有结束了,又一次被右边的同桌虐了(额,排名第三的大佬)但是考试还是进步了一名,算是有进步吧

    成绩:

    那个12名就是我,一个AC都没有,太难受了。

    T1:

    题目链接:http://hzoi.com/contest/39/ranklist/1(内部题库,不确保能进入)

    题目:

    题目是一个简化版,很水,直接2的16次方枚举就完了。

    当时不知到咋回事居然TLE 60(尬);

    直接看代码吧:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    //monsters;
    int a[5][5],data[5][5];
    int lowbit(int x){
    	return x&-x;
    }
    int get(int x){
    	int num=0;
    	for(int j=x;j>0;j-=lowbit(j)){
    		num++;
    	}
    	return num;
    }
    void gai(int x,int y){
    	a[x][y]^=1;
    	a[x+1][y]^=1;
    	a[x-1][y]^=1;
    	a[x][y-1]^=1;
    	a[x][y+1]^=1;
    }
    void clear(){
    	for(int i=1;i<=4;i++){
    		for(int j=1;j<=4;j++){
    			a[i][j]=data[i][j];
    		}
    	}
    }
    bool pan(){
    	int c=a[1][1];
    	for(int i=1;i<=4;i++){
    		for(int j=1;j<=4;j++){
    			if(a[i][j]!=c)return 0;
    		}
    	}
    	return 1;
    }
    int main(){
    //	freopen("a.in","r",stdin);
    	std::ios::sync_with_stdio(false);//cin cout 的优化
    	std::cin.tie(0);
    	for(int i=1;i<=4;i++){//预处理
    		for(int j=1;j<=4;j++){
    			char c;cin>>c;
    			if(c=='b')a[i][j]=data[i][j]=1;
    			else a[i][j]=0;
    		}	
    	}
    	int ans=110;
    	for(int i=0;i<(1<<16);i++){//暴力枚举每个点是否翻转 1翻转 0 不反转
    		int cnt=get(i);
    		int num=0;
    		int j=i;
    		while(i>0){
    			if((i&1)==1){
    				int x=num/4+1;int y=(num+4)%4+1;//计算出点的坐标
    				gai(x,y);	
    			}
    			num++;
    			i=i>>1;
    		}
    		if(pan()){
    			//printf("%d ",cnt);
    			ans=min(ans,cnt);
    		}
    		clear();
    		i=j;
    	}
    	if(ans==110){
    		cout<<"Impossible";return 0;
    	}	
    	cout<<ans;
    	return 0;
    }
    

    当然还有更加优化的做法,详见洛谷P1764

    T2:

    题目来自于洛谷P3627[APIO2009] 题目链接:https://www.luogu.com.cn/problem/P3627

    题目:

    这题太水了,一眼救出思路:Tarjan+最短路

    当时我忘了跑最短路,直接爆搜的,TLE 80pts.

    几个注意点:

    1.最短路能用Dij ,不符合DIj 原理。

    2.实际上是个最长路,可以点权变负再跑。

    OK 代码:

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int maxn=500005;
    struct edge{
    	int from,to,next;
    }e[500005];
    struct node{
    	int to,next;
    }v[500005];
    int vhead[maxn],cnt;
    int head[maxn],ans,shu[maxn];
    void insert(int x,int y){
    	e[++ans].from=x;e[ans].to=y;e[ans].next=head[x];head[x]=ans;
    }
    int dfn[maxn],low[maxn],dfs_clock;
    int sta[maxn],top,belong[maxn],scc_cnt,siz[maxn];
    void dfs(int u){
    	dfn[u]=low[u]=++dfs_clock;
    	sta[++top]=u;
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(!dfn[v]){
    			dfs(v);
    			low[u]=min(low[u],low[v]);
    		}else if(!belong[v])low[u]=min(low[u],dfn[v]);
    	}
    	if(dfn[u]==low[u]){
    		++scc_cnt;
    		while(1){
    			int x=sta[top--];
    			belong[x]=scc_cnt;
    			siz[scc_cnt]+=shu[x];
    			if(x==u)break;
    		}
    	}
    }
    int dis[500005],scnt[500005],ing[500005];
    queue<int> q;
    bool SPFA(int s,int n){
    	for(int i=1;i<=n;i++){
    		dis[i]=0x3f3f3f3f;scnt[i]=0;
    	}
    	scnt[s]=1;dis[s]=siz[s];q.push(s);ing[s]=1;
    	while(!q.empty()){
    		int u=q.front();q.pop();ing[u]=0;
    		for(int i=vhead[u];i;i=v[i].next){
    			int t=v[i].to;
    			if(dis[t]>dis[u]+siz[t]){
    				dis[t]=dis[u]+siz[t];
    				if(!ing[t]){
    					if(++scnt[t]>=n)return 0;
    					ing[t]=1;q.push(t);
    				}
    			}
    		}
    	}
    	return 1;
    }
    int main(){
    	int n,m;scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		int x,y;scanf("%d%d",&x,&y);
    		insert(x,y);
    	}
    	for(int i=1;i<=n;i++){
    		int x;scanf("%d",&x);
    		shu[i]=-x;
    	}
    	int s,p;scanf("%d%d",&s,&p);
    	dfs(s);
    	for(int i=1;i<=m;i++){
    		int x=e[i].from,y=e[i].to;
    		if(belong[x]!=belong[y]){
    			v[++cnt].to=belong[y];
    			v[cnt].next=vhead[belong[x]];
    			vhead[belong[x]]=cnt;
    		}
    	}
    	int flag=SPFA(belong[s],scc_cnt);
    	int Max=-1;
    	for(int i=1;i<=p;i++){
    		int x;scanf("%d",&x);
    		Max=max(Max,-dis[belong[x]]);
    	}
    	printf("%d",Max);
    	return 0;
    }
    

    T3:

    题目来源:洛谷P2933 [USACO09JAN]The Baric Bovine G 链接:https://www.luogu.com.cn/problem/P2933

    这道题其实挺难的。

    一开始首先想DFS暴搜,后来算一下100!发现不现实。

    那么只能想 DP 了

    首先只能定义状态:

    f[i][j]为前i个书选择j个的最小误差。

    显然的f[i][j]=min(f[i][j],f[k][j-1]+?);

    那么?是啥?

    我们可以预处理出数组pre[i][j] 表示 原序列 中 Mi ,Mj 是所选的的相邻的两个元素,则i 到 j 之间元素对误差的贡献 ,显然我们可以n3暴力枚举 轻松得出

    我们用pre[i][0] 表示如果Mi 是序列第一个数,则M1 ——Mi-1 的误差之和,同理pre[i][n+1] 表示Mi 作为最后一个元素的情况。

    然后就可以转移了。

    f[i][j]=min(f[i][j],f[k][j-1]-pre[k][n+1]+pre[i][n+1]+pre[k][i]);

    然后有一些细节代码中展示

    代码:

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn=105;
    int n,m;
    int a[maxn],pre[maxn][maxn];
    int f[maxn][maxn];
    int cnt=101,Max=0x3f3f3f3f;
    int main(){
    	//freopen("a.in","r",stdin);
    	std::ios::sync_with_stdio(false);
    	std::cin.tie(0);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}	
    	for(int i=1;i<=n;i++){
    		for(int j=i+1;j<=n;j++){
    			for(int k=i+1;k<j;k++){
    				pre[i][j]+=abs(2*a[k]-a[i]-a[j]);
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int k=1;k<i;k++){
    			pre[i][0]+=2*abs(a[k]-a[i]);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int k=i+1;k<=n;k++){
    			pre[i][n+1]+=2*abs(a[k]-a[i]);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		f[1][i]=pre[i][0]+pre[i][n+1];
    		if(f[1][i]<=m){
    			cnt=1;Max=min(Max,f[1][i]);
    		}	
    	}
    	if(cnt==1){
    		cout << cnt <<' '<< Max;return 0;
    	}
    	for(int i=2;i<=n;i++){
    		for(int j=i;j<=n;j++){
    			f[i][j]=0x3f3f3f3f;
    			for(int k=i-1;k<j;k++){
    				f[i][j]=min(f[i][j],f[i-1][k]-pre[k][n+1]+pre[j][n+1]+pre[k][j]);
    			}
    			if(f[i][j]<=m){
    				if(i>cnt)continue;
    				if(i<cnt){
    					cnt=i;Max=f[i][j];
    				}
    				else if(i==cnt)Max=min(Max,f[i][j]);
    			}
    		}
    	}
    	cout<<cnt<<' '<<Max;
    	return 0;
    }
    

    T4 :

    原题来自于洛谷P3963 [TJOI2013] 奖学金  题目链接:https://www.luogu.com.cn/problem/P3963

    题目:

    题目很好理解:我当时最先想出来了二分答案,

    其实二分答案是不对的,错误样例请自己证明

    那么这道题该如何做,

    大家可以参考一下 洛谷上黑匣子一题

    应该就会找到思路。

    下面是代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #define ll long long
    using namespace std;
    const int maxn=200005;
    int n,m;ll p;
    struct node{
    	ll dis,money;
    }e[maxn];
    bool cmp(node a,node b){
    	return a.dis<b.dis;
    }
    priority_queue<ll> q;
    ll f[maxn],d[maxn];
    int main(){
    	//freopen("a.in","r",stdin);
    	std::ios::sync_with_stdio(false);
    	std::cin.tie(0);
    	cin>>n>>m>>p;
    	for(int i=1;i<=m;i++){
    		cin>>e[i].dis>>e[i].money;
    	}
    	sort(e+1,e+m+1,cmp);
    	ll sum=0;
    	for(int i=1;i<=n/2;i++){
    		q.push(e[i].money);
    		sum+=e[i].money;
    	}
    	for(int i=n/2+1;i<=m;i++){
    		f[i]=sum;
    		int x=e[i].money;
    		int top=q.top();
            if(top>e[i].money){
                q.pop();
                sum-=top;
                sum+=e[i].money;
                q.push(e[i].money);
            }
    	}
    	sum=0;
    	while(q.size())q.pop();
    	for(int i=m;i>=m-n/2+1;i--){
    		q.push(e[i].money);
    		sum+=e[i].money;
    	}
    	for(int i=m-n/2;i>=1;i--){
    		d[i]=sum;
    		int top=q.top();
    		if(top>e[i].money){
                q.pop();
                sum-=top;
                sum+=e[i].money;
                q.push(e[i].money);
            }
    	}
    	for(int i=m-n/2;i>=1+n/2;i--){		
    		if(f[i]+d[i]+e[i].money<=p){
    			cout<<e[i].dis;return 0;
    		}
    	}
    	cout<<"-1";
    	return 0;
    }
    

    OK  今天总结到此结束了。

    希望明天能冲进前十

  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/DZN2004/p/13203759.html
Copyright © 2011-2022 走看看