• [20181017][模拟赛]


    题目

    T1

    思路

    统计每列有多少个1。如果(sum[0]geqslant sum[1]),那么ans的这一位为0,否则为1。

    预计得分:100

    实际得分:100

    代码

    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    const int N = 1010;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
     	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * f;
    }
    int a[N];
    char s[N];
    int main() {
    	freopen("curse.in","r",stdin);
    	freopen("curse.out","w",stdout);
    	int n = read();
    	int L;
    	for(int i = 1;i <= n;++i) {
    		scanf("%s",s+1);
    		L = strlen(s + 1);
    		for(int j = 1;j <= L;++j)
    			a[j] += s[j] - '0'; 
    	}
    	for(int i = 1; i <= L; ++i) {
    		if(a[i] > n/2) printf("1");
    		else printf("0");
    	}
    	return 0;
    }
    

    T2

    20分思路

    首先,分析一下题目,其实R和G的数据范围是假的。因为这个题可以转化为将这个序列分为R+G段,其中小于L的段必须大于等于R。并且所有的段都要小于2*L。那么如果R+G>=n,可以直接输出1,就有了20分。

    60-70分思路

    一般看到题目就能想到二分答案,把L二分出来,然后check。考虑怎样check。继续上面的思路思考,把这个题想成是“将这个序列分为R+G段,其中小于L的段必须大于等于R。并且所有的段都要小于2L”。然后考虑dp转移,用f[i][j]表示前i个分为j段(保证每段都小于等于2L)其中小于等于L的段的个数最后只要判断f[n][R+G]是不是大于等于R就行了。

    转移方程:(f[i][j]=f[k][j-1]+(a[i]-a[k+1])<L (0leqslant k leqslant i-1))

    60-70分代码

    //f[i][j]表示前i段分成j段每段都小于等于2L,小于等于L的段的数量。
    //如果f[n][R+G] < R表示no,否则为yes 
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    const int N = 2010,INF = 1000000000 + 100;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * f;
    }
    int R,G;
    int a[N];
    int f[N][N*2];
    int n;
    int check(int L) {
    	memset(f,-1,sizeof(f));
    	f[0][0] = 0;
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1;j <= R + G; ++j) {
    			for(int k = i - 1;k >= 0; --k) { 
    				if(a[i] - a[k + 1] >= 2 * L ) break;
    				if(f[k][j-1] == -1) continue;
    				f[i][j] = max(f[i][j],f[k][j - 1] + (a[i] - a[k + 1] < L));
    				f[i][j] = max(f[i][j],f[i][j - 1]);
    			}
    		}
    	}
    	return f[n][R + G] >= R ;
    }
    int main() {
    //	freopen("light.in","r",stdin);
    //	freopen("light.out","w",stdout);
    	n = read(),R = read(), G = read();
    	if(R + G >= n) {
    		puts("1");
    		return 0;
    	}
    	a[n+1] = INF;
    	for(int i = 1;i <= n; ++i) a[i] = read();
    	sort(a + 1, a + n + 1);
    	int l = 1, r = a[n];
    	int ans = 0;
    	while(l <= r) {
    		int mid = (l + r) >> 1;
    		if(check(mid)) ans = mid, r = mid - 1;
    		else l = mid + 1;
    	}
    	cout<<ans;
    //	check(4);
    	return 0;
    }
    

    假的100思路

    在上面的基础上加上一些优化。首先需要把dp中的i和j的枚举顺序颠倒,也就是先枚举j再枚举i,然后发现每一层都是从上一层转移过来的,所以压掉第一维。然后就有可以发现可以用单调队列优化。然后就可以愉快的再(O(n^2))的时间复杂度中进行dp。

    调了一个下午好不容易调出来,竟然80分fu*k!!!

    正解

    看完正解才知道自己多么zz。用f[i][j]表示用了i次L,j次2L可以调到的最远距离。用q[i]表示从i开始用L跳一步可以跳到的最远距离,p[i]表示从i开始用2L跳一步可以跳到的最远距离。转移的时候(f[i][j]=max(q[f[i-1][j]+1],p[f[i][j-1]+1]))

    最后判断f[R][G]是不是大于等于n就行了。

    预计得分 50

    实际得分 70

    ac代码

    //f[i][j]表示前i段分成j段每段都小于等于2L,小于等于L的段的数量。
    //如果f[n][R+G] < R表示no,否则为yes 
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    const int N = 20010,INF = 1000000000 + 100;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * f;
    }
    int R,G;
    int a[N];
    int f[N];
    int n;
    int qL[N],q2L[N],qLhead,q2Lhead,qLtail,q2Ltail;
    int check(int L) {
    	memset(f,-1,sizeof(f));
    	f[0] = 0;
    	for(int j = 1;j <= R + G; ++j) {
    		qLhead = q2Lhead = 1;
    		qLtail = q2Ltail = 0;
    		int nowL = n - 1,now2L = n - 1;
    		for(int i = n; i >= 1; --i) {
    			while(qL[qLhead] >= i && qLhead <= qLtail) 
    			qLhead++;
    			while(a[i] - a[nowL + 1] < L && nowL >= 0) {
    				while(f[qL[qLtail]] <= f[nowL] && qLtail >= qLhead) 
    				qLtail--;
    				qL[++qLtail] = nowL--;
    			} 
    			while(q2L[q2Lhead] >= i && q2Lhead <= q2Ltail) 
    			q2Lhead++;
    			while(a[i] - a[now2L + 1] < 2 * L && now2L >= 0) {
    				while(f[q2L[q2Ltail]] <= f[now2L] && q2Ltail >= q2Lhead) 
    				q2Ltail--;
    				q2L[++q2Ltail] = now2L--;				
    			}
    			int k1 = qL[qLhead],k2 = q2L[q2Lhead];
    			if(f[k1] != -1) f[i] = max(f[i],f[k1] + 1);
    			if(f[k2] != -1) f[i] = max(f[i],f[k2]);
    		}
    		f[0] = -1;
    	}
    	return f[n] >= R ;
    }
    int main() {
    	n = read(),R = read(), G = read();
    	if(R + G >= n) {
    		puts("1");
    		return 0;
    	}
    	a[n+1] = INF;
    	for(int i = 1;i <= n; ++i) a[i] = read();
    	sort(a + 1, a + n + 1);
    	int l = 1, r = a[n];
    	int ans = 0;
    	while(l <= r) {
    		int mid = (l + r) >> 1;
    		if(check(mid)) ans = mid, r = mid - 1;
    		else l = mid + 1;
    	}
    	cout<<ans;
    	return 0;
    }
    

    真AC代码

    //f[i][j]表示前i段分成j段每段都小于等于2L,小于等于L的段的数量。
    //如果f[n][R+G] < R表示no,否则为yes 
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define fi(s) freopen(s,"r",stdin);
    #define fo(s) freopen(s,"w",stdout);s
    using namespace std;
    typedef long long ll;
    const int N = 2010,INF = 1000000000 + 100;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * f;
    }
    int f[N][N],a[N],R,G,q[N],p[N],n;
    int check(int L) {
    	memset(f,0,sizeof(f));
    	for(int i = 1; i <= n;++i) {
    		for(int j = i;j <= n;++j) {
    			if(a[j] - a[i] + 1 <= L) q[i] = j;
    			if(a[j] - a[i] + 1<= L*2) p[i] = j;
    		}
    	}
    	q[n + 1] = n; p[n + 1] = n;
    	for(int i = 0;i <= R; ++i) {
    		for(int j = 0;j <= G; ++j) {
    			if(i - 1 >= 0) f[i][j] = max(f[i][j], q[f[i - 1][j] + 1]);
    			if(j - 1 >= 0) f[i][j] = max(f[i][j], p[f[i][j - 1] + 1]);
    		}
    	}
    	return  f[R][G] >= n;
    }
    int main() {
    	fi("light.in");
    	fo("light.out");
    	n = read(),R = read(), G = read();
    	if(R + G >= n) {
    		puts("1");
    		return 0;
    	}
    	a[n+1] = INF;
    	for(int i = 1;i <= n; ++i) a[i] = read();
    	sort(a + 1, a + n + 1);
    	int l = 1, r = a[n];
    	int ans = 0;
    	while(l <= r) {
    		int mid = (l + r) >> 1;
    		if(check(mid)) ans = mid, r = mid - 1;
    		else l = mid + 1;
    	}
    	cout<<ans;
    	return 0;
    }
    

    T3

    思路

    次短路的模板。从1节点和n节点分别跑最短路,然后枚举条边x,用dis[1][x]+w[x]+dis[x][n],从中取最小并且不等于最短路的即可。

    然而freopen写成了这样$$freopen("maze.out","w",stout)$$

    愉快的ce了

    预计得分 80

    实际得分 0

    代码

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N = 10010;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * f;
    }
    struct node {
    	int u,v,nxt,w;
    }e[100000 * 2 +100];
    int ejs = -1,head[N],fa[N];
    void add(int u,int v,int w) {
    	e[++ejs].u = u,e[ejs].v = v;e[ejs].w = w; e[ejs].nxt = head[u];head[u] = ejs;
    }
    int n,m;
    queue<int>q;
    int vis[N];
    ll dis[4][N];
    void spfa(int U,int bz) {
    	while(!q.empty()) q.pop();
    	memset(vis,0,sizeof(vis));
    	q.push(U);
    	dis[bz][U] = 0;
    	while(!q.empty()) {
    		int u = q.front();
    		vis[u] = 0;
    		q.pop();
    		for(int i = head[u];i != -1;i = e[i].nxt) {
    			int v = e[i].v;
    			if(dis[bz][v] > dis[bz][u] + e[i].w) {
    				dis[bz][v] = dis[bz][u] + e[i].w;
    				if(!vis[v]) {
    					q.push(v);
    					vis[v] = 1;
    				}
    			}
    		}
    	}
    	return ;
    }
    int main() {
    	freopen("maze.in","r",stdin);
    	freopen("maze.out","w",stdout);
    	n = read(),m = read();
    	memset(head,-1,sizeof(head));
    	memset(dis,0x3f,sizeof(dis));
    	for(int i = 1;i <= m;++i) {
    		int u =read(),v = read(),w = read();
    		add(u,v,w);	add(v,u,w);
    	}
    	spfa(1,1);
    	spfa(n,2);
    	int k = dis[1][n];
    	ll ans = 0x7fffffff;
    	for(int i = 0;i <= ejs;++i)
    		ans = dis[1][e[i].u] + dis[2][e[i].v] + e[i].w == k ? ans : min(ans,dis[1][e[i].u] + dis[2][e[i].v] + e[i].w);
    	cout<<ans;
    	return 0;
    }
    

    一言

    我愿以身化剑……永生永世护你周全! ——无限恐怖

  • 相关阅读:
    PyCharm 3.4注册码
    监控Oracle索引是否被启用
    Oracle execute plan 原理分析与实例分享(转)
    6 个重构方法可帮你提升代码质量(转载)
    跟我一起学Oracle 11g【2】----用户管理(转载)
    notecore设置linux/Unix系统文件权限
    Unicode特殊字符的坑
    net多线程
    走过的HttpClient坑
    Postgre备份还原
  • 原文地址:https://www.cnblogs.com/wxyww/p/9806612.html
Copyright © 2020-2023  润新知