联赛模拟测试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\n",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\n",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\n",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\n",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\n",f[n][ans]);
	Print(n,ans);
	return 0;
}

挂分:\(30pts+\)

posted @ 2020-10-13 16:57  HH_Halo  阅读(157)  评论(0编辑  收藏  举报