首页 > 其他分享 >231019校内赛

231019校内赛

时间:2023-10-19 21:14:14浏览次数:45  
标签:校内 int ++ 231019 mp ans col define

T1 机器人

piigoBq.jpg

题解

傻逼题,但是有人 \(90\) 分

一开始十分想直接暴力 \(2^n\) 判断每一步选不选求出所有可能性

但是会发现它有制约关系有些步走了之后,有些就必须走了

所以需要用一个数组记录当前位置走没走过,或者是不是障碍

注意走没走过不能直接赋值 \(1,0\) 因为回溯时会直接将前面的标记也改没了

还要注意的一点是对于部分实现来说遍历顺序很重要,可能会卡住几个点

也是因为标记顺序导致的,容易破坏之前的标记导致状态错误

#include<bits/stdc++.h>
#define N 40
using namespace std;
int n,ans,g[N<<1][N<<1],vis[N<<1][N<<1];
char s[N];
void dfs(int p,int x,int y){
	if(p==n+1){
		if(!g[x][y])ans++;
		g[x][y] = 1;
		return ;
	}
	int fx = x,fy = y;
	switch(s[p]){
		case'L':x--;break;
		case'R':x++;break;
		case'U':y++;break;
		case'D':y--;break;
	}
	if(vis[x][y]==0){
		vis[x][y] = -1;
		dfs(p+1,fx,fy);
		vis[x][y] = 1;
		dfs(p+1,x,y);
		vis[x][y]=0; 
	}
	else if(vis[x][y]==-1)dfs(p+1,fx,fy);
	else if(vis[x][y]==1)dfs(p+1,x,y);
}
int main(){
	freopen("robot.in","r",stdin);
	freopen("robot.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>s+1;vis[n][n]=1;
	dfs(1,n,n);
	cout<<ans<<"\n";
	for(int i = 0;i<=n*2;i++)
		for(int j = 0;j<=n*2;j++)
			if(g[i][j]) cout<<i-n<<" "<<j-n<<"\n";
	return 0;
}

T2 旅行

piihWOH.jpg

题解

先考虑是一棵树的情况时色块数的贡献,我们以每个节点为分界点计算答案

该节点对答案的贡献即为不同颜色的数目减一,对于每次修改操作,统计节点的增量即可

基环树是一个环上每一个节点连接了一棵树,和树的情况类似

节点的贡献是相同计算的,同时要考虑环多出的那一条边对答案的贡献,如果整个环上只有一种颜色, 答案还要加一

只需使用 \(map\) 代替二维数组记录每个点内不同颜色的数量,再 \(dfs\) 找出所有环上的边,判断这些边的颜色是否相同即可统计单次答案

一次修改最多改一条边上的值,所以可以方便的进行单点修改同时维护答案

#include<bits/stdc++.h>
#define N 200010
using namespace std;
int n,q,rt,col[N],hcol[N],h[N];
bool vis[N];
vector<int>g[N];
map<pair<int,int>,int>id;
map<int,int>mp[N];
int dfs(int u,int fa){
	vis[u] = 1;
	int x = 0;
	for(int v : g[u]){
		if(v==fa) continue;
		if(!vis[v]){
			int tmp = dfs(v,u);
			if(tmp){
				int fu = u,fv = v;
				if(fu>fv) swap(fu,fv);
				h[id[{fu,fv}]] = 1;
				x = tmp;
			}
			if(tmp==u) x = 0;
		}else if(v!=rt){
			int fu = u,fv = v;
			if(fu>fv) swap(fu,fv);
			h[id[{fu,fv}]] = 1;
			rt = u;x = v;
		}
	}
	return x;
}
int main(){
	freopen("tour.in","r",stdin);
	freopen("tour.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--){
		cin>>n>>q;rt = 0;
		id.clear();
		for(int i = 1;i<=n;i++){
			g[i].clear();mp[i].clear();
			h[i] = vis[i] = hcol[i] = 0;
		}
		for(int i = 1;i<=n;i++){
			int u,v,w;
			cin>>u>>v>>w;
			if(u>v) swap(u,v);
			id[{u,v}] = i;
			col[i] = w;
			mp[u][w]++;mp[v][w]++;
			g[u].push_back(v);
			g[v].push_back(u);
		}
		dfs(1,0);
		int ans = 0;
		for(int i = 1;i<=n;i++)
			ans+=mp[i].size()-1;
		int hsize = 0;
		for(int i = 1;i<=n;i++)
			if(h[i]) hsize++;
		for(int i = 1;i<=n;i++){
			if(h[i]){
				hcol[col[i]]++;
				if(hcol[col[i]]==hsize) ans++;
			}
		}
		for(int i = 1;i<=q;i++){
			int u,v,w;
			cin>>u>>v>>w;
			if(u>v) swap(u,v);
			int p = id[{u,v}];
			if(h[p]){
				if(hcol[col[p]]==hsize) ans--;
				hcol[col[p]]--;
				hcol[w]++;
				if(hcol[w]==hsize) ans++;
			}
			mp[u][col[p]]--;
			if(!mp[u][col[p]]) ans--;
			if(!mp[u][w]) ans++;
			mp[u][w]++;
			mp[v][col[p]]--;
			if(!mp[v][col[p]]) ans--;
			if(!mp[v][w]) ans++;
			mp[v][w]++;
			col[p] = w;
			cout<<ans<<"\n";
		}
	}
	return 0;
}

T3 点餐

pii5daR.jpg

题解

将所有输入先按照 \(b\) 排序,枚举第 \(x\) 道菜作为最大的 \(b\) 值的答案,贪心选择前面 \(k-1\) 个 \(a\) 更小的即可

可以通过可持久化线段树 \(\mathcal O(\log n)\) 求出答案 \(f_{k,x}\)

设 \(g_k\) 表示选择 \(k\) 个时最优解是选择 \(x\) 作为 \(b\) 最大

对于两个决策 \(x,y(x<y)\) 如果 \(f_{x,k} \ge f_{y,k}\) 那么对于 \(k(k\le x)\) ,\(y\) 的选择范围一定包含 \(x\) 的选择范围,因此 \(y\) 选的 \(a\) 值一定不大于 \(x\) 选的

所以有 \(g_1 \le g_2 \le g_3 \ldots \le g_n\) ,也就是具有决策单调性,可以分治求解

时间复杂度为 \(\mathcal O(n \log ^2 n)\)

#include<bits/stdc++.h>
#define int long long
#define N 200010
#define M ((60*N)+5)
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
struct node{
	int l,r,dat,sum;
}t[M];
int n,m,cnt,tot,hs[N],rt[N],ans[N];
pii a[N];
bool cmp(pii x,pii y){
	return x.se<y.se;
}
void newnode(int &v){
	t[++cnt].dat = t[v].dat;
	t[cnt].sum = t[v].sum;
	t[cnt].l = t[v].l;
	t[cnt].r = t[v].r;
	v = cnt;
}
void insert(int x,int &v,int l,int r){
	newnode(v);
	t[v].dat++;
	t[v].sum+=hs[x];
	if(l==r) return ;
	int mid = (l+r)>>1;
	if(x<=mid) insert(x,t[v].l,l,mid);
	else insert(x,t[v].r,mid+1,r);
}
int query(int p,int v,int l,int r){
	if(l==r) return p*hs[l];
	int mid = (l+r)>>1;
	if(t[t[v].l].dat>=p) return query(p,t[v].l,l,mid);
	else  return t[t[v].l].sum+query(p-t[t[v].l].dat,t[v].r,mid+1,r);
}
void calc(int x,int y,int l,int r){
	if(l>r||x>y) return ;
	int mid = (l+r)>>1,p = 0;
	ans[mid] = 1e18;
	for(int i = max(x,mid);i<=y;i++){
		int w = a[i].se+query(mid,rt[i],1,tot);
		if(w<ans[mid]) ans[mid] = w,p = i;
	}
	calc(x,p,l,mid-1);
	calc(p,y,mid+1,r);
}
signed main(){
	freopen("order.in","r",stdin);
	freopen("order.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i = 1;i<=n;i++){
		cin>>a[i].fi>>a[i].se;
		hs[i] = a[i].fi;
	}
	sort(hs+1,hs+n+1);
	tot = unique(hs+1,hs+n+1)-hs-1;
	for(int i = 1;i<=n;i++)
		a[i].fi = lower_bound(hs+1,hs+tot+1,a[i].fi)-hs;
	sort(a+1,a+n+1,cmp);
	for(int i = 1;i<=n;i++){
		rt[i] = rt[i-1];
		insert(a[i].fi,rt[i],1,tot);
	}
	calc(1,n,1,n);
	for(int i = 1;i<=n;i++)
		cout<<ans[i]<<"\n";
	return 0;
}

又是不会T4的一天

标签:校内,int,++,231019,mp,ans,col,define
From: https://www.cnblogs.com/cztq/p/17775642.html

相关文章

  • 231019校内赛
    T1购买饮料题解简单且傻逼的题目有人更傻逼没做出来很容易就会想去拿最后能喝多少瓶去做未知量来求然后就有一个严重的问题,它会赊账非常明显这样算是不得行的那么考虑换个思路以能喝多少套饮料为未知量,先除去第一套,免得一套都买不起时赊账买了饮料然后将剩余的钱除以\(......
  • [校内]此方(konata)
    2023-10-14题目LittleBrother题目描述难度&重要性(1~10):7题目来源CQYC题目算法几何,二分解题思路Sol我们知道,对于两个圆,我们无非就只有三种情况:相离,相切,相交。而这道题目是不允许其他圆相交,而两个圆不相交只有两种情况:包含,不包含。根据垂径定理得知,过线段两端的圆的......
  • 231011校内赛
    T1树上的数题解比上一次好一些的第一题不过我还是没做出来一眼树形\(dp\)不过状态设计和转移不是很好列容易想到对于子树枚举,记录\(f_{i,j}\)表示\(i\)的子树空出了\(j\)个点时的方案数对于每一个节点的初始状态都是\(f_{i,0}=n-dep_i\\\f_{i,1}=1\)为......
  • 231009校内赛
    T1里群题解阴间第一题题目中有一个很明显的建图方法就是对于第\(i\)天入群的人在第\(j\)天退群那么就在\(i,j\)之间连一条边首先有一个结论,管理员个数不大于\(3\)对于这个结论,证明如下:首先第一次删除出现后就一定需要两个管理员了如果某次删除只删掉了某一个管理......
  • 231007校内赛
    T1karma题解首先从贪心的思路出发把所有零多的字符串放在前面,但如下一组数据便可以卡掉201100接着我们可以来思考对于贪心的更改多举几组不同的可以卡掉的样例后可以发现如下规律先将所有字符串按\(0\)的数量排一遍序对于每一个字符串的\(0\)和\(1\)的数量我......
  • 231004校内赛
    T1水管题解很简单的一道题,别想复杂了只要一边\(dfs\)即可先将当前点的所有水量给出去,如果缺水就给出去负数那么等到最后一个节点如果不是刚好合适,那么就把剩余水量回溯回来,无论正负再如此给下一个连边的点如果最后一个点刚好合适那么给下一个点的就是\(0\)实现很简单......
  • 231002校内赛
    T1数独题解十分简单的一道模拟题有sb少打了一个换行挂50分#include<bits/stdc++.h>#defineN15usingnamespacestd;structnode{ inta[N][N],be;}t[N*10];intT,n=9,q;intferror(intcnt,intx,inty,intk){ for(inti=1;i<=n;i++) if(t[cnt].a[x][i]==k)......
  • 230930校内赛
    T1洛阳怀题解首先非常容易求出的是所有的\(\gcd\)对于\(\gcd\)而言,如果它的分数是负数,那么将它除去一定会使这个数列得分变大所以只用求出所有的\(\gcd\)的分数并判断正负以及是否除过当前答案了就可以了还有一点是因为\(\gcd\)是单调不降的,所以可以从后往前查保证......
  • 2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(同步赛)
    A.AXorBProblem(计数)输入511223输出9说明点击查看代码#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false);cin.tie(0),cout.tie(0)#defineintlonglongusingnamespacestd;constintN=2e5+10;unordered_map<int,int>......
  • 230925校内赛
    T1开挂我卢本伟没有开挂题解挺简单的,不过我写的比较麻烦因为我们需要让多的尽可能多来让少的尽可能少,所以会想到用栈来存储需要更改的数,靠近栈底就需要更多次数来更改,栈顶则更少最后只用记录下来所有的次数并按从多到少依次分配从小到大的修改代价#include<bits/stdc++.h......