zoukankan      html  css  js  c++  java
  • 联赛模拟测试15

    (T1) 游戏

    思路分析

    • 考场的时候用贪心贪过了,正确性是可以保障的,只是时间效率差了点。先排序,每一组默认选最小的,然后再看每一组大的里如果没出现过,就看与它同一组的可不可以换成它。考场吸氧了,所以可以过。
    • 并查集和二分图也都可以过,后来又写了一遍二分图的,跑的飞快。当然需要一个小技巧:不必使用memset,只需改变一个 (now) 值,用 (now) 值判断 vis 数组

    (Code in the test)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<map>
    #include<vector>
    #define N 1000010
    #define R register
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n;
    struct data{
    	int x,y;
    	inline bool operator <(const data &a)const{
    		return x==a.x ? y < a.y : x < a.x;
    	}
    }a[N];
    map<int,int>vis;
    vector<int>v[N];
    int main(){
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	n = read();
    	for(R int i = 1;i <= n;i++){
    		a[i].x = read(),a[i].y = read();
    		if(a[i].x > a[i].y)swap(a[i].x,a[i].y);
    	}
    	sort(a+1,a+1+n);
    	for(R int i = 1;i <= n;i++){
    		vis[a[i].x]++;
    		v[a[i].y].push_back(a[i].x);
    	}
    	for(R int i = 1;i <= n;i++){
    		if(!vis[a[i].y]){
    			if(vis[a[i].x]>1)vis[a[i].x]--,vis[a[i].y]++;
    			else if(vis[a[i].x]==1){
    				int mx = 0,res = 0;
    				for(R int j = 0;j < v[a[i].x].size();j++){
    					if(vis[v[a[i].x][j]]>mx)mx = vis[v[a[i].x][j]],res = j;
    				}
    				if(mx>1)vis[v[a[i].x][res]]--,v[a[i].x][res] = 0,vis[a[i].y]++;
    			}
    		}
    	}
    	int ans = 0;
    	for(R int i = 1;i <= n;i++){
    		if(!vis[i])break;
    		ans++;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    (Better Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<map>
    #include<vector>
    #define N 1000010
    #define R register
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,head[N],vis[N],now,match[N];
    struct edge{
    	int to,next;
    }e[N<<1];
    int len;
    void addedge(int u,int v){
    	e[++len].to = v;
    	e[len].next = head[u];
    	head[u] = len;
    }
    bool find(int x){
    	for(R int i = head[x];i;i = e[i].next){
    		int v = e[i].to;
    		if(vis[v]==now)continue;//小技巧
    		vis[v] = now;
    		if(!match[v]||find(match[v])){
    			match[v] = x;
    			return 1;
    		}
    	}
    	return 0;
    }
    int main(){
    #if 0
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    #endif
    	n = read();
    	for(R int i = 1;i <= n;i++){
    		int x = read(),y = read();
    		addedge(x,i),addedge(y,i);
    	}
    	int ans = 0;
    	for(R int i = 1;i <= n;i++){
    		now = i;//不用memset
    		if(find(i))ans = i;
    		else break;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    (T2) 嘟嘟噜

    思路分析

    • 前几天刚考过一次约瑟夫问题,自信的写完然后看了一眼数据范围整个人傻掉。
    • 原递推公式是 (x=(x+m)\%i)。打表的时候发现了需要快速算出下次取模的位置,然而没有想出来怎么写……
    • (i) 轮需要 (\%i),所以可以算出上一个答案在达到 (i) 时需要加几个 (m),当然不能超过 (n-i) 个。然后 (i) 就可以快速跳跃了

    Code

    
    
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #define N 1000010
    #define R register
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m;
    int main(){
    #if 1
    	freopen("mayuri.in","r",stdin);
    	freopen("mayuri.out","w",stdout);
    #endif
    	int t = read();
    	while(t--){
    		n = read(),m = read();
    		int x = 0;
    		for(R int i = 1;i <= n;i++){
    			int tmp = min((i-x)/m-1,n-i-1);
    			if(tmp>0&&tmp<n)x += tmp*m,i += tmp;
    			x = (x+m)%i;
    		}
    		printf("%d
    ",x+1);
    	}
    	return 0;
    }
    
    

    (T3) 天才绅士少女助手克里斯蒂娜

    思路分析

    • 推柿子,因为挨个码柿子太费时间了所以不码了(其实是推不动),最后答案就是 (sum x*sum y-(sum x*y)^2),树状数组就行了,线段树也行,但能用树状数组为什么要用线段树呢

    (Code)

    
    
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define N 1000010
    #define R register
    #define ll long long
    using namespace std;
    inline ll read(){
    	ll x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    const int mod = 20170927;
    int n,m;
    ll c[N][3];
    struct Speed{
    	ll x,y;
    }v[N];
    void update(ll x,ll val,int id){
    	for(;x<=n;x+=x&(-x))c[x][id] = (c[x][id]+val+mod)%mod;
    }
    ll query(ll x,int id){
    	ll res = 0;
    	for(;x;x-=x&(-x))res = (res+c[x][id])%mod;
    	return res;
    }
    ll get_ans(int l,int r,int id){
    	return (query(r,id)-query(l-1,id)+mod)%mod;
    }
    int main(){
    #if 1
    	freopen("kurisu.in","r",stdin);
    	freopen("kurisu.out","w",stdout);
    #endif
    	n = read(),m = read();
    	for(R int i = 1;i <= n;i++){
    		v[i].x = read(),v[i].y = read();
    		update(i,v[i].x*v[i].x%mod,0);
    		update(i,v[i].y*v[i].y%mod,1);
    		update(i,v[i].x*v[i].y%mod,2);
    	}
    	for(R int i = 1;i <= m;i++){
    		int opt = read();
    		if(opt==1){
    			ll p = read(),x = read(),y = read();
    			update(p,(x*x%mod-v[p].x*v[p].x%mod+mod)%mod,0);
    			update(p,(y*y%mod-v[p].y*v[p].y%mod+mod)%mod,1);	
    			update(p,(x*y%mod-v[p].x*v[p].y%mod+mod)%mod,2);
    			v[p].x = x,v[p].y = y;
    		}else{
    			int l = read(),r = read();
    			ll a = get_ans(l,r,0),b = get_ans(l,r,1),c = get_ans(l,r,2);
    			ll ans = (a*b%mod-c*c%mod+mod)%mod;
    			printf("%lld
    ",ans);
    		}
    	}
    	return 0;
    }
    
    

    (T4) 凤凰院凶真

    思路分析

    • (LCS+LIS = LCIS)。考场上写了个 (O(n^4)) 的暴力 (DP),结果因为忽略了等于,导致捆绑测试全部爆零,怒送 (30)分,kuku
    • 正解是 (O(n^2)) 的,首先枚举 (a[i]),然后在遍历 (b) 数组的过程中只需要记录一个小于 (a[i]) 的且答案最优的 (b) 数组的位置既可
    • 输出路径,只需记录每个状态是由哪个状态转移来的,递归输出即可

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define R register
    #define N 5010
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m,a[N],b[N],f[N][N],mx,ans,path[N][N];
    void Print(int x,int y){
    	if(!x)return;
    	Print(x-1,path[x][y]);
    	if(path[x][y]!=y)printf("%d ",b[y]);
    }
    int main(){
    #if 1
    	freopen("phoenix.in","r",stdin);
    	freopen("phoenix.out","w",stdout);
    #endif
    	n = read();
    	for(R int i = 1;i <= n;i++)a[i] = read();
    	m = read();
    	for(R int i = 1;i <= m;i++)b[i] = read();
    	for(R int i = 1;i <= n;i++){
    		for(R int j = 1,k = 0;j <= m;j++){
    			if(a[i]==b[j]){
    				f[i][j] = f[i-1][k]+1;
    				path[i][j] = k;
    			}else{
    				f[i][j] = f[i-1][j];
    				path[i][j] = j;
    			}
    			if(b[j]<a[i]&&f[i][j]>f[i][k])k = j;
    		}
    	}
    	for(R int i = 1;i <= m;i++){
    		if(f[n][i]>f[n][ans])ans = i;
    	}
    	printf("%d
    ",f[n][ans]);
    	Print(n,ans);
    	return 0;
    }
    

    挂分:(30pts+)

  • 相关阅读:
    Alfred上可提高工作效率的Workflow推荐
    局部性原理——各类优化的基石
    持续学习——程序猿的军备竞赛
    http://regex.alf.nu/ 非标准答案
    13总结
    Ubuntu下python安装mysqldb(驱动)
    北大ACM试题分类+部分解题报告链接
    poj 3253 Fence Repair(优先队列+huffman树)
    Centos/Fedora下安装Twisted,failed with error code 1 in /tmp/pip-build-H1bj8E/twisted/解决方法
    关于command 'gcc' failed with exit status 1 解决方法
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13809862.html
Copyright © 2011-2022 走看看