首页 > 其他分享 >CSPS-2023

CSPS-2023

时间:2023-10-28 15:23:07浏览次数:33  
标签:ch return int CSPS long 2023 tid define

密码锁(lock)

考场想推一个复杂度牛逼的东西,后来发现直接 \(O(10^5)\) 枚举状态,\(O(40)\) 判断合不合法就行了。并且我考场降智了,我乘上了一个 \(O(2^8)\) 枚举每个状态推到这八种密码是用哪种操作,但其实可以不用判断的,因为我们只关心行不行,不关心是用的哪种操作。但是因为我加了一些减枝所以 \(O(10^5 \times 2^8 \times 40)\) 跑的还挺快。

code:

#include<bits/stdc++.h>
//#define int long long
#define ll long long
#define re register
#define il inline

using namespace std;

int n,ans;
int p[10],c[10],a[10][10];

il int read()
{
	int f = 0 , s = 0;
	char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(; isdigit(ch);ch=getchar()) s = (s<<1)+ (s<<3) + (ch-'0');
	return f ? -s : s;
}

il void check()
{
	int cnt = 0 , pos1 = 0 , pos2 = 0;
	for(re int i=1;i<=n;i++)
	{
		if(c[i] == 1)
		{
			cnt = 0;
			for(re int j=1;j<=5;j++) if(a[i][j] != p[j]) cnt++;
			if(cnt > 1) return ;
		}
		if(c[i] == 2)
		{
			cnt = pos1 = pos2 = 0;
			for(re int j=1;j<=5;j++)
			{
				if(a[i][j] != p[j])
				{
					cnt++;
					if(cnt >= 3) return ;
					if(!pos1) pos1 = j;
					else pos2 = j;
				}
			}
			if(pos1+1 != pos2) return ;
			if(((a[i][pos1]-p[pos1]+10) % 10) != ((a[i][pos2]-p[pos2]+10) % 10)) return ;
		}
	}
	ans++;
}

il bool judge(int i)
{
	int cnt = 0;
	for(re int j=1;j<=5;j++) if(a[i][j] != p[j]) cnt++;
	if(cnt > 1) return 0;
	else return 1;
}

il void dfs2(int id)
{
	if(id == n+1)
	{
		check();
		return ;  
	}
	if(judge(id))
	{
		c[id] = 1 , dfs2(id+1);
		c[id] = 2 , dfs2(id+1);
	}
	else c[id] = 2 , dfs2(id+1);
}

il void dfs1(int id)
{
	if(id == 6)
	{
		bool flag = 0;
		for(re int i=1;i<=n;i++)
		{
			flag = 0;
			for(re int j=1;j<=5;j++)
				if(a[i][j] != p[j]) { flag = 1; break; }
			if(!flag) return ;
		}
		dfs2(1);
		return ;
	}
	for(re int i=0;i<=9;i++)
	{
		p[id] = i;
		dfs1(id+1); 
	}
}

signed main()
{
	//freopen("lock.in","r",stdin);
	//freopen("lock.out","w",stdout);
	n = read();
	for(re int i=1;i<=n;i++)
		for(re int j=1;j<=5;j++) 
			a[i][j] = read();
	if(n == 1) { cout << 81; return 0; }
	dfs1(1);
	cout << ans;
	return 0;
}

消消乐(game)

首先容易想到一个 \(O(n^2)\) 算法:我们枚举左端点,然后从左端点开始往右扫,每次扫的时候开一个栈,如果当前栈顶和要加进来的字母是同一个字母,就把栈顶 pop 掉,否则将这个字母入栈。如果在某一时刻栈是空的,这说明从左端点到这个时刻的这一段区间就是可消的,我们让答案++。

我们考虑怎么优化这个过程,如果在某一时刻栈是空的,这也就说明,在此时,栈顶的状态和在左端点时的状态是一样的。于是,我们就可以只需要从 \(1\) 开始从左往右扫一遍,每次加入一个新的字母时,判断它之前有多少个时候的状态跟它是一样的,这个我们可以通过 hash 来实现这个状态的存储,然后用一个桶来存储每个状态的数目,这么做即可做到近乎线性。因为 unordered_map 不被卡的话是 \(O(1)\) 的,所以可以通过 \(2\times 10^6\)。

code:

#include<bits/stdc++.h>
#define int unsigned long long
#define ull unsigned long long
#define ll long long
#define re register
#define il inline
const int N = 2e6 + 5;
const int base = 191;
using namespace std;

int n,top,ans;
ull Hash[N];
char ch[N];
struct STACK{
	char ch;
	int id;
}stk[N];
unordered_map <ull,int> t;

il int read()
{
	int f = 0 , s = 0;
	char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(; isdigit(ch);ch=getchar()) s = (s<<1)+ (s<<3) + (ch-'0');
	return f ? -s : s;
}

signed main()
{
	n = read();
	cin >> (ch+1);
	t[0] = 1;
	for(re int i=1;i<=n;i++)
	{
		if(!top)
		{
			stk[++top] = {ch[i],i};
			Hash[i] = ch[i] - '0';
			ans += t[Hash[i]] , t[Hash[i]]++;
		}
		else
		{
			if(stk[top].ch == ch[i])
			{
				top--;
				Hash[i] = Hash[stk[top].id];
				ans += t[Hash[i]] , t[Hash[i]]++;
			}
			else
			{
				Hash[i] = Hash[stk[top].id] * base + (ch[i] - '0');
				stk[++top] = {ch[i],i};
				ans += t[Hash[i]] , t[Hash[i]]++;
			}
		}
		//cout << Hash[i] << " ";
	}
	cout << ans;
	return 0;
}

结构体(struct)

神必模拟,不想多说啥,抄的我叠 MichaelWong 的代码,大模拟做不了一点,里面有我大叠给我的一些注释。

#include<bits/stdc++.h>
#define int long long
#define ll long long
#define next nxt
#define re register
#define il inline
#define pii pair <int,int>
#define pis pair <ll,string>
const int N = 150 + 5;
using namespace std;
int max(int x,int y){return x > y ? x : y;}
int min(int x,int y){return x < y ? x : y;}

int n,opt,varcnt=3; //varcnt 动态记录变量类型总数
int totaddr,size[N],alisz[N];//内存占用情况,不同类型的大小和他们的对齐要求
vector <pis> varlist; //存地址的结束点(不包含这个点)和变量名
map <string,int> varid; //通过类型名获取类型编号 (id)
map <string,pii> address; // 通过名字获取地址起始点(包含这个点)和他的类型 id
// 一个 type 型变量 name,他占据了 [l,r) 的内存空间,则 varist 存的 r,address 存了 l
struct structure{
	vector <pis> varlist;
	map <string,pii> address;
}str[N];

il int read()
{
	int f=0,s=0;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(; isdigit(ch);ch=getchar()) s = (s<<1) + (s<<3) + (ch^48);
	return f ? -s : s;
}

il void declare_struct()
{
	string name,type;
	int addr = 0,nxt,k,tid;
	cin >> type >> k;
	varid[type] = ++varcnt;
	str[varcnt].varlist.resize(k);
	for(re int i=0;i<k;i++)
	{
		cin >> type >> name;
		tid = varid[type];
		if(addr % alisz[tid]) nxt = addr / alisz[tid] * alisz[tid] + alisz[tid];
		else nxt = addr;
		str[varcnt].address[name] = {nxt,tid};
		str[varcnt].varlist[i] = {addr=nxt+size[tid],name};
		alisz[varcnt] = max(alisz[varcnt],alisz[tid]);
	}
	if(addr % alisz[varcnt]) size[varcnt] = addr / alisz[varcnt] * alisz[varcnt] + alisz[varcnt];
	else size[varcnt] = addr;
	cout << size[varcnt] << " " << alisz[varcnt] << "\n";
	return ;
}

il void declare_variable()
{
	string name,type;
	cin >> type >> name;
	int tid = varid[type];
	ll nxt;
	if(totaddr % alisz[tid]) nxt = totaddr / alisz[tid] * alisz[tid] + alisz[tid];
	else nxt = totaddr;
	address[name] = {nxt,tid};
	varlist.push_back({totaddr=nxt+size[tid],name});
	cout << nxt << "\n";
	return ;
}

il void visit_element()
{
	string s,now;
	cin >> s , s = " " + s;
	int len=s.length()-1,pos=0,nxt=len+1,tid,nxtid;//pos是已找到的上一个 ".",nxt 是最新找到的 "."
	int addr = 0;
	for(re int i=pos+1;i<=len;i++) if(s[i] == '.') { nxt = i; break ; }
	now = s.substr(pos+1,nxt-pos-1);
	auto pr = address[now];//找到地址起始点和类型 id
	tid = pr.second , addr += pr.first , pos = nxt , nxt = len + 1;
	while(pos != len+1)//进入结构体内部
	{
		for(re int i=pos+1;i<=len;i++) if(s[i] == '.') { nxt = i; break ; }
		now = s.substr(pos+1,nxt-pos-1);
		pr = str[tid].address[now];
		nxtid = pr.second , addr += pr.first , pos = nxt , nxt = len + 1;
		tid = nxtid;
	}
	cout << addr << "\n";
	return ;
}

il void visit_address()
{
	int addr = 0;
	int tid,nxtid;
	string s="",now;
	cin >> addr;
	if(varlist.empty()) { puts("ERR"); return ; }
	if(addr >= (*--varlist.end()).first) { puts("ERR"); return ; }
	auto pr = *upper_bound(varlist.begin(),varlist.end(),pis{addr,"zzzzzzzzzz"});
	now = pr.second , tid = address[now].second , addr -= pr.first-size[tid] , s += now;
	if(addr < 0) { puts("ERR"); return ; }
	while(tid > 3)
	{
		s += '.';
		if(addr >= (*--str[tid].varlist.end()).first) { puts("ERR"); return ; }
		pr = *upper_bound(str[tid].varlist.begin(),str[tid].varlist.end(),pis{addr,"zzzzzzzzzz"});
		now = pr.second , nxtid = str[tid].address[now].second , addr -= pr.first-size[nxtid] , s += now;
		tid = nxtid;
		if(addr < 0) { puts("ERR"); return ; }
	}
	cout << s << "\n";
	return ; 
}

signed main()
{
	n = read();
	varid["byte"] = 0 , varid["short"] = 1 , varid["int"] = 2 , varid["long"] = 3;
	for(re int i=0;i<=3;i++) size[i] = alisz[i] = (1<<i);
	for(re int i=1;i<=n;i++)
	{
		opt = read();
		if(opt == 1) declare_struct();
		if(opt == 2) declare_variable();
		if(opt == 3) visit_element();
		if(opt == 4) visit_address();
	}
	return 0;
}

种树(tree)

首先这个答案肯定是具有单调性的,所以我们可以想到二分。它问的是最少需要多少天完成任务,那我们就二分这个结束时间。

然后就是怎么分配哪天种哪个地方的树了。首先我们可以等比数列求和公式等东西 + 分类讨论求出当结束时间为 \(x\) 时,第 \(i\) 号地块最晚在第几天种上树,可以在结束时间前长到需求高度,我们记为 \(day_i\)。

但是这时我们想一下,这个 \(day_i\) 的定义其实是不那么好的,我们考虑,如果 \(x\) 的孩子 \(y\) 的 \(day_y\) 要 \(\ge day_x\),那么为了 \(y\)
能种上树,\(x\) 的最晚起始时间是需要提前的,也就是 \(\displaystyle day_x = \min(day_x,\min_{y\in son(x)}\{day_y-1\})\),一遍 dfs 求出即可。

我们贪心地考虑,显然,对于 \(day_i\) 较大的地块,我们可以让他往后稍稍,让 \(day_i\) 较小的种上树,这样才能最大化的满足要求。我们可以通过维护一个小根堆来实现这个过程。最后如果说种树成功了,那就说明这个结束时间可以,然后根据结果修改一下 \(l,r\) 即可,时间复杂度 \(O(n\log^2n)\)。

有如下细节需要注意:

  • 因为题目中保证 \(ans \leq 10^9\),所以我们的二分边界只需要设到 \(10^9\) 而不是再往大了走,因为我的代码里二分里又套了个二分,所以这个边界不同,常数会有大不同。最初做的时候没有看到这个保证,我开的 \(r = 10^{14}\),喜提 TLE \(70\)pts。

  • 在使用等比数列求和公式的时候,可能会出现爆 long long 的情况,这时候就有一个小妙招 by xwh_Marvelous:如果爆 long long,那肯定就是这个变量值变负数了,因为题目中 \(a_i \leq 10^9\),所以爆 long long 肯定说明这个最晚的开始时间是合法的,判一下是否是负数就行了。

#include<bits/stdc++.h>
#define int long long
#define ll long long
#define re register
#define il inline
const int N = 1e5 + 5;
using namespace std;

int n,u,v;
ll sum,fir,sec;
ll h[N],b[N],c[N],Late[N];
bitset <N> vis;
struct node{
	ll day,id;
	bool operator <(const node &t) const {
		return day > t.day; 
	}
};
vector <int> G[N];

il int read()
{
	int f = 0 , s = 0;
	char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(; isdigit(ch);ch=getchar()) s = (s<<1)+ (s<<3) + (ch-'0');
	return f ? -s : s;
}//O(n!) can't get 20pts,but O(nlog^2n) can get 100pts

il bool GetSum(int i,int day,int lastday)
{
	if(b[i] + day * c[i] >= 1)
	{
		if(c[i] == 0)
		{
			sum = b[i] * (lastday-day+1);
			if(sum < 0) sum = 1e18;
			if(sum >= h[i]) return true;
			else return false;
		}
		if(c[i] > 0)
		{
			fir = b[i] + day * c[i] , sec = b[i] + lastday * c[i];
			sum = (fir+sec)*(lastday-day+1)/2;
			if(sum < 0) sum = 1e18;
			if(sum >= h[i]) return true;
			else return false;
		}
		if(c[i] < 0)
		{
			int midday = min((b[i]-1)/(-c[i]),lastday);
			fir = b[i] + day * c[i] , sec = b[i] + midday * c[i];
			sum = (fir+sec)*(midday-day+1)/2 + (lastday-midday);
			if(sum >= h[i]) return true;
			else return false;
		}
	}
	else
	{
		if(lastday-day+1 >= h[i]) return true;
		else return false;
	}
	return true;
}

il int GetAns(int i,int lastday)
{
	int l = 1 , r = lastday , ans = 0;
	while(l <= r)
	{
		int mid = (l+r) >> 1;
		if(GetSum(i,mid,lastday)) ans = mid , l = mid + 1;
		else r = mid - 1;
	}
	return ans;
}

il void dfs(int x,int fa)
{
	for(re auto y : G[x])
	{
		if(y == fa) continue;
		dfs(y,x);
		Late[x] = min(Late[x],Late[y]-1);
	}
}

il bool check(int lastday)
{
	priority_queue <node> q;
	vis.reset();
	for(re int i=1;i<=n;i++)
	{
		Late[i] = GetAns(i,lastday);
		if(!Late[i]) return false;
	}
	dfs(1,0);
	for(re int i=1;i<=n;i++) if(!Late[i]) return false;
	vis[1] = 1;
	for(re auto x : G[1]) q.push({Late[x],x});
	for(re int i=2;i<=n;i++)
	{
		if(q.empty()) return false;
		int x = q.top().id; q.pop();
		if(Late[x] < i) return false;
		vis[x] = 1;
		for(re auto y : G[x]) if(!vis[y]) q.push({Late[y],y});
	}
	return true;
}

signed main()
{
	n = read();
	for(re int i=1;i<=n;i++) h[i] = read() , b[i] = read() , c[i] = read();
	for(re int i=1;i<n;i++)
	{
		u = read() , v = read();
		G[u].push_back(v) , G[v].push_back(u);
	}
	int l = 1 , r = 1e9 , 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;
}

标签:ch,return,int,CSPS,long,2023,tid,define
From: https://www.cnblogs.com/bloodstalk/p/17794103.html

相关文章

  • 2023-2024-1 20211306 密码系统设计与实现课程学习笔记7
    20211306密码系统设计与实现课程学习笔记7任务详情自学教材第4章,提交学习笔记知识点归纳以及自己最有收获的内容,选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容“我在学***X知识点,请你以苏格拉底的方式对我进行提问,一次一个问题......
  • NOIP2023模拟5联测26 题解
    NOIP2023模拟5联测26题解感觉我这场的官方题解写的是真的挺好的,所以我只能作少量补充。你可以直接去看官方题解,如果你想的话。T1x题解\(n=2\)没啥可说的。\(\color{white}{这档分你要是没拿到那你还是蛮强的。}\)\(n=3\)的时候,我们需要比较\((a_1^{a_2})^{a_3}\)与......
  • SolidEdge2023激活版下载 中文特别版
    SolidEdgeST20功能介绍1、加速你的3D建模拥有更快,更灵活的3D零件和装配建模、扩大利用同步的建模技术、逼真的渲染和增强的2D绘图制作能力,使您能够设计出更好的产品,并且这些产品将领先竞争对手的市场。2、强化了3D草图3D草图可在零件、装配体和钣金环境中加快许多建模场景,例如,通过......
  • 2023.10 ~ 夜已承载心无眠 再巨大的伤悲皆已成灰
    https://www.bilibili.com/video/BV1yX4y1P7Kd「其實沒有那麼特別。我不想把自己定義在樂觀或悲觀的圈圈裡我就是我。我想成為一個追尋所愛就能投注心力的人,即便最後沒有如願,我也會大哭一場,宣洩不滿不甘心不認同,再好好記住這份「得來不易」的回憶。我知道,我沒有那麼特別......
  • 2023-2024-1 20231312《计算机基础与程序设计》第5周学习总结
    作业信息这个作业属于哪个课程<班级的链接>2023-2024-1-计算机基础与程序设计|-这个作业要求在哪里<作业要求链接>2023-2024-1计算机基础与程序设计第四周作业|这个作业的目标《计算机基础概论》第6章《C语言程序设计》第4章|作业正文作业链接教材学习......
  • php反序列化2023/10/28
    题目来源:[第五空间2021]pklovecloud题目代码如下:<?phpinclude'flag.php';classpkshow{functionecho_name(){return"Pkverysafe^.^";}}classacp{protected$cinder;public......
  • 20231005比赛
    T14883.灵知的太阳信仰Description在炽热的核熔炉中,居住着一位少女,名为灵乌路空。据说,从来没有人敢踏入过那个熔炉,因为人们畏缩于空所持有的力量——核能。核焰,可融真金。咳咳。每次核融的时候,空都会选取一些原子,排成一列。然后,她会将原子序列分成一些段,并将每段进行一次......
  • 2023-2024-1 20231414《计算机基础与程序设计》第5周学习总结
    学期(2023-2024-1)学号(20231414)《计算机基础与程序设计》第五周学习总结作业信息这个作业属于哪个课程<班级的链接>(2023-2024-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(2023-2024-1计算机基础与程序设计第五周作业)这个作业的目标<Pep/9虚拟机,......
  • 2023-2024-1 20231405 《计算机基础与程序设计》第五周总结
    2023-2024-120231405《计算机基础与程序设计》第五周总结作业信息作业属于哪个课程https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP作业要求在哪里https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP/homework/13009作业的目标自学《计算机科学......
  • 「Log」2023.10.27 小记
    序幕\(\text{6:50}\):到校,早上稍微墨迹了一小会。一直不会的某个结论差不多会证明了,先写一下题再写写题解。\(\color{blueviolet}{CF1495D}\)此题是好题。考虑对于\(x\)和\(y\)共同的生成树一定包含两者的最短路径。先假设\(x,y\)最短路径有且只有一条,考虑其上一点\(......