首页 > 其他分享 >241116 noip 模拟赛

241116 noip 模拟赛

时间:2024-11-16 16:57:33浏览次数:1  
标签:head const noip int ans ecnt 模拟 241116 dp

省流:\(100 + 100 + 100 + 5\)。

T1

题意:给一个括号序列 \(s\),求出长度最小的 \(s\) 的子序列 \(t\),满足 \(t\) 是合法括号序列且删掉 \(t\) 后 \(s\) 是一个特殊的序列。定义特殊的序列为长度 \(2n\),前 \(n\) 个都是 (,后 \(n\) 个都是 )

\(n \leq 3 \times 10^6\)。

可以枚举特殊序列左右括号的分界点,有个比较显然的贪心就是往左一个一个加入左括号看合不合法,往右一个一个加入右括号看合不合法。这具有单调性,所以可以双指针。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=3e6+5;
string s;
int a[N],l[N],r[N];
bool check() {
	int sum=0;
	for(int i=0; i<s.size(); i++) {
		sum+=(s[i]=='(');
		sum-=(s[i]==')');
		if(sum<0) return false;
	}
	return sum==0;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>s;int n=s.size();
	if(!check()) return cout<<-1,0;
	int tot=0,pos=1,sum1=0,sum2=0;
	for(int i=0; i<n-1; i++) {
		if(s[i]=='(') a[++tot]=0;
		else a[tot]++,sum2++;
		while(pos<=tot&&sum1<sum2) {
			sum1+=(a[pos]==0);
			sum2-=a[pos];
			pos++;
		}
		l[i]=tot-pos+1;
	}
	tot=sum1=sum2=0;pos=1;
	for(int i=n-1; i>0; i--) {
		if(s[i]==')') a[++tot]=0;
		else a[tot]++,sum2++;
		while(pos<=tot&&sum1<sum2) {
			sum1+=(a[pos]==0);
			sum2-=a[pos];
			pos++;
		}
		r[i-1]=tot-pos+1;
	}
	int ans=0;
	for(int i=0; i<n-1; i++) ans=max(ans,min(l[i],r[i]));
	cout<<n-2*ans;
	return 0;
}

T2

原题:AT_cf17_final_g。

最优策略:每次选取第⼀个 \(a_i = i\) 的位置,然后操作,这样不会破坏已经可以操作的位置的性质,同时可以尽可能多地操作。

分析发现,每次操作会把整个序列的总和 \(-1\)。所以可以考虑计算出所有不同初始值下 \(-i\) 的方案数总和。本质上就是计算出了所有情况下减去的总和。再用所有方案数的总和减去这个方案数就得到最终所有情况的答案。

而每个点只会被后⾯的点操作,于是我们倒着 dp,记 \(dp_{i,j}\) 表示到了第 \(i\) 位,它后面的位置总共对它造成了 \(j\) 次 \(+1\) 的操作”的方案数,然后我们枚举第 \(i\) 位的初始值 \(x\),如果可以操作那么⼀定可以在 \(i\) 处操作了 \(\lfloor \frac{x + j}{i} \rfloor\) 次操作,可以操作代表的是初始值 \(\leq i\)。那么最后怎么统计答案呢?发现 \(dp_{1,i}\),也就是 \(1\) 被 \(+1\) 的次数为i时,总体是⼀共做了 \(i\) 次总和 \(-1\),所以所有减去的 \(1\) 的总和就是 \(\sum dp_{1,i} \times i\)。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=105,p=1e9+7;
int n,k,dp[N][N*N],ans=0;
int qpow(int a,int b) {
	int ans=1;
	while(b) {
		if(b&1) ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
}
signed main() {
	cin>>n>>k;
	dp[k][0]=k,dp[k][1]=1;
	for(int i=k; i>1; i--) {
		for(int j=0; j<=k*k; j++) {
			for(int l=0; l<i; l++) if(j+(l+j)/(i-1)<=k*k) (dp[i-1][j+(l+j)/(i-1)]+=dp[i][j])%=p;
			(dp[i-1][j]+=dp[i][j]*(k-i+1)%p)%=p;
		}
	}
	for(int i=1; i<=n; i++) (ans+=k*(k+1)/2*qpow(k+1,n-1)%p)%=p;
	for(int i=0; i<=k*k; i++) (ans+=-dp[1][i]*i%p*qpow(k+1,n-k)%p+p)%=p;
	cout<<ans;
	return 0;
}

T3

原题:CF177G2。

对于 \(n \leq 28\),直接暴力做就行。接下来讨论 \(n > 28\) 的情况。

对于一个字符串,设它在 \(f_i\) 的出现次数为 \(g_i\),那么有 \(g_i = g_{i - 1} + g_{i - 2} + x\),\(x\) 表示这个字符串在 \(f_i\) 出现次数减 \(f_{i - 1}\) 出现次数减 \(f_{i - 2}\) 出现次数,即跨越 \(f_{i - 1}\) 和 \(f_{i - 2}\) 的出现次数。观察一下,发现 \(i\) 为奇数时,\(f_i\) 可以被表示为 \(\cdots + f_{26} + f_{26} + \cdots\),最中间的即为 \(f_{i - 1}\) 和 \(f_{i - 2}\) 的分界点;当 \(i\) 为偶数时,\(f_i\) 可以被表示为 \(\cdots + f_{27} + f_{26} + \cdots\),分界点同理。由于 \(f_{26}\) 已经大于 \(10^5\) 了,所以 \(x\) 只分奇数和偶数两种取值,算出这两种取值按照上面的递推式矩阵快速幂优化即可。

暴力和算 \(x\) 我用了 ACM 解决。好像可以用其他的,应该是我赛时唐了。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,p=1e9+7;
string s[N];
int n,q,tot=0,ch[N][2],fl[N],cnt[N],id[N],head[N],ecnt=0;
struct node {int to,nxt;}e[N];
void addedge(int u,int v) {e[++ecnt]=(node){v,head[u]};head[u]=ecnt;}
struct matrix {
	int c[6][6];
	matrix operator*(const matrix &o) const {
		matrix x;
		memset(x.c,0,sizeof(x.c));
		for(int i=1; i<=5; i++)
			for(int j=1; j<=5; j++)
				for(int k=1; k<=5; k++)
					x.c[i][j]=(x.c[i][j]+c[i][k]*o.c[k][j]%p)%p;
		return x;
	}
}a,ans[N];
matrix qpow(matrix a,int b) {
	matrix ans;
	memset(ans.c,0,sizeof(ans.c));
	for(int i=1; i<=5; i++) ans.c[i][i]=1;
	while(b) {
		if(b&1) ans=ans*a;
		a=a*a;
		b>>=1;
	}
	return ans;
}
void add(string s,int ii) {
	int cur=0;
	for(int i=0; i<s.size(); i++) {
		int b=s[i]-'0';
		if(!ch[cur][b]) ch[cur][b]=++tot;
		cur=ch[cur][b];
	}
	id[ii]=cur;
}
void build_fail() {
	queue<int> q;
	for(int i=0; i<2; i++) if(ch[0][i]) q.push(ch[0][i]);
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		for(int i=0; i<2; i++) {
			if(ch[u][i]) fl[ch[u][i]]=ch[fl[u]][i],q.push(ch[u][i]);
			else ch[u][i]=ch[fl[u]][i];
		}
	}
}
void query(string t) {
	int cur=0;
	for(int i=0; i<t.size(); i++) {
		int b=t[i]-'0';
		cur=ch[cur][b];
		cnt[cur]++;
	}
}
void dfs(int u) {
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		dfs(v);cnt[u]+=cnt[v];
	}
}
string make(int lim) {
	string s1="0",s2="1",s3;
	for(int i=3; i<=lim; i++) {
		s3=s2+s1;
		s1=s2,s2=s3;
	}
	return s3;
}
void init1() {
	a.c[1][1]=0,a.c[1][2]=0,a.c[1][3]=0,a.c[1][4]=0,a.c[1][5]=0;
	a.c[2][1]=0,a.c[2][2]=1,a.c[2][3]=1,a.c[2][4]=0,a.c[2][5]=0;
	a.c[3][1]=1,a.c[3][2]=1,a.c[3][3]=2,a.c[3][4]=0,a.c[3][5]=0;
	a.c[4][1]=0,a.c[4][2]=1,a.c[4][3]=1,a.c[4][4]=1,a.c[4][5]=0;
	a.c[5][1]=0,a.c[5][2]=0,a.c[5][3]=1,a.c[5][4]=0,a.c[5][5]=1;
}
void init2(string t,int ii) {
	query(t);dfs(0);
	for(int i=1; i<=q; i++) ans[i].c[1][ii]+=cnt[id[i]];
	memset(cnt,0,sizeof(cnt));
}
signed main() {
	freopen("fib.in","r",stdin);
	freopen("fib.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>q;
	for(int i=1; i<=q; i++) cin>>s[i],add(s[i],i);
	build_fail();
	for(int i=1; i<=tot; i++) addedge(fl[i],i);
	if(n<=28) {
		string t=make(n);
		query(t);dfs(0);
		for(int i=1; i<=q; i++) cout<<cnt[id[i]]<<'\n';
	} else {
		string t1=make(26),t2=make(27),t3=make(28);
		init1(),init2(t1,1),init2(t2,2),init2(t3,3),init2(t1+t1,4),init2(t2+t1,5);
		for(int i=1; i<=q; i++) ans[i].c[1][4]-=2*ans[i].c[1][1],ans[i].c[1][5]-=ans[i].c[1][1]+ans[i].c[1][2];
		matrix tmp=qpow(a,(n-27)/2);
		for(int i=1; i<=q; i++) {
			ans[i]=ans[i]*tmp;
			if(n&1) cout<<ans[i].c[1][2]<<'\n';
			else cout<<ans[i].c[1][3]<<'\n';
		}
	}
	return 0;
}

T4

原题:P6305。

洛谷题解讲的挺好,不写了,其实是懒得写

代码:

#include<bits/stdc++.h> 
#define endl '\n'
using namespace std;
const int N=4e5+5;
vector<int> ve;
int n,s,a[N],b[N],c[N],vis[N],vise[N],nxt[N],head[N],ecnt=0;
struct node {int to,nxt;}e[N];
void add(int u,int v) {e[++ecnt]=(node){v,head[u]};head[u]=ecnt;} 
void dfs(int u) {
	for(int& i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(vise[i]) continue;
		vise[i]=true,dfs(v);
	}
	if(u<=n) ve.push_back(u),vis[u]=true;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>s;
	for(int i=1; i<=n; i++) cin>>a[i],b[i]=a[i];
	sort(b+1,b+n+1);
	int len=unique(b+1,b+n+1)-b-1;
	for(int i=1; i<=n; i++) a[i]=lower_bound(b+1,b+len+1,a[i])-b,c[i]=a[i];
	sort(c+1,c+n+1);
	for(int i=1; i<=n; i++) {
		if(a[i]==c[i]) continue;
		add(i,n+a[i]);add(n+c[i],i);
	}
	vector<vector<int>> tmp;
	for(int i=1; i<=n; i++) {
		if(vis[i]||a[i]==c[i]) continue;
		ve.clear();dfs(i);
		ve.pop_back();s-=ve.size();
		reverse(ve.begin(),ve.end());
		tmp.push_back(ve);
	}
	if(s<0) return cout<<-1,0;
	if(!tmp.size()) return cout<<0,0;
	if(tmp.size()==1) {
		cout<<1<<endl<<tmp[0].size()<<endl;
		for(int i=0; i<tmp[0].size(); i++) cout<<tmp[0][i]<<" ";
		return 0;
	}
	if(s>=tmp.size()) {
		cout<<2<<endl;
		cout<<tmp.size()<<endl;
		for(int i=0; i<tmp.size(); i++) cout<<tmp[i][0]<<" ";
		cout<<endl;
		int sum=0;
		for(int i=0; i<tmp.size(); i++) sum+=tmp[i].size();
		cout<<sum<<endl;
		for(int i=0; i<tmp.size(); i++) {
			for(int j=1; j<tmp[i].size(); j++) nxt[tmp[i][j]]=tmp[i][(j+1)%tmp[i].size()];
			nxt[tmp[i][0]]=tmp[(i-1+tmp.size())%tmp.size()][1];
		}
		int cur=tmp[0][0];
		do cout<<cur<<" ",cur=nxt[cur]; while(cur!=tmp[0][0]);
	} else {
		cout<<tmp.size()-max(0,s-1)+(s>=2)<<endl;
		if(s>=2) {
			cout<<s<<endl;
			for(int i=0; i<s; i++) cout<<tmp[i][0]<<" ";
			cout<<endl;
			int sum=0;
			for(int i=0; i<s; i++) sum+=tmp[i].size();
			cout<<sum<<endl;
			for(int i=0; i<s; i++) {
				for(int j=1; j<tmp[i].size(); j++) nxt[tmp[i][j]]=tmp[i][(j+1)%tmp[i].size()];
				nxt[tmp[i][0]]=tmp[(i-1+s)%s][1];
			}
			int cur=tmp[0][0];
			do cout<<cur<<" ",cur=nxt[cur]; while(cur!=tmp[0][0]);
			cout<<endl;
		}
		for(int i=(s==1?0:s); i<tmp.size(); i++) {
			cout<<tmp[i].size()<<endl;
			for(int j=0; j<tmp[i].size(); j++) cout<<tmp[i][j]<<" ";
			cout<<endl;
		}
	}
	return 0;
}

标签:head,const,noip,int,ans,ecnt,模拟,241116,dp
From: https://www.cnblogs.com/System-Error/p/18549508

相关文章

  • NOIP集训 P4137 Rmq Problem / mex 题解
    前置指使:可持久化线段树题解:P4137RmqProblem/mex有一个长度为\(n\)的数组\(\{a_1,a_2,...,a_n\}\)。\(m\)次询问,每次询问一个区间内最小没有出现过的自然数。Input第一行,两个正整数\(n,m\)。第二行,\(n\)个非负整数\(a_1,a_2,...,a_n\)。接下来\(m\)行,每......
  • 蓝桥杯模拟赛(第一期)个人题解&感想
    林专大一牲第一次写blog,更新较慢,写的不好的地方请见谅(好多题目忘记了题号and暂时没有题目要求的内容…后面会补充的!)本次带来的是蓝桥杯模拟赛第一期的个人题解(笨人水平较低,大家可以在评论区指出错误/讨论更优解~)大多题我是用c++写的,但也掺了几道c,为以后全面用c++打比赛作过......
  • CSP/信奥赛C++语法基础刷题训练(9):洛谷P1035:[NOIP2002 普及组] 级数求和
    CSP/信奥赛C++语法基础刷题训练(9):洛谷P1035:[NOIP2002普及组]级数求和题目描述已知:Sn=1......
  • CSP/信奥赛C++语法基础刷题训练(10):洛谷P1307:[NOIP2011 普及组] 数字反转
    CSP/信奥赛C++语法基础刷题训练(10):洛谷P1307:[NOIP2011普及组]数字反转题目描述给定一个整数NNN,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,......
  • [DMY]2024 NOIP 模拟赛 Day 9
    比赛7:30开始,我8:10到的机房。赛时T1看了一眼后以为是双指针,然后开始写,写到一半发现假飞了。想了一会发现除了随机化以外没有任何思路,所以写个\(n^2\)暴力就扔了。去看T2,像是个DP题。先把组合数复杂度的暴力写了,发现不太好写。我用了\(n\)遍dikstra,但其实用Floyd......
  • 1116及1115模拟赛
    \(T1\),大师,我悟了(doge)。树上问题可转化为二维偏序关系,一维是题目中要求的大小关系(也可以是等于),一维是数上某序关系(常为dfs序),用数据结构维护或扫描线等维护一个维,处理另一维。这道题考虑询问时每个结点由哪些节点贡献来。当\(u\)是\(v\)的祖先(dfs序关系)且\(dep[v]-dep[u]=time[v......
  • 炼石计划 NOIP 模拟赛 #20
    A.\(kx+(\sum_{i=1}^{k}a_i-1)\timesy=k(x-y)+y\times\sum_{i=1}^{k}a_i\)\((a_1-1)*1+(a_2-1)*(a_1-1)*1+(a_3-1)*(a_2-1)*(a_1-1)*1\)$\prod_{i=1}^{k}a_i>N$两数和相等时乘积最大,因此\(a\)数组中任意两个数的差的绝对值......
  • CloudCompare——CSF布料模拟算法
    布料模拟算法1、流程概述2、详细过程3、参考文献4.软件实现5.相关链接1、流程概述1)利用点云滤波算法或者点云处理软件滤除异常点;2)将激光雷达点云倒置;3)设置模拟布料,设置布料网格分辨率GR......
  • NOIP2024 前集训:NOIP2024加赛 5
    前言music《浮光》看指尖拨响蝴蝶扇动一场离别我推开无声岁月续梦一页你我只是打个照面可曾有过誓约走进熟悉却陌生的思念啊……啊……你的眼眸装满了时间你的身后拥故事成篇此生如梦愿细数流年与你同写沧海桑田浮光掠影重山彩云间你的伏线......
  • 『模拟赛』NOIP2024加赛5
    Rank反向挂分大王A.暴力操作(opt)签,但是没有人签。都想到了二分和更新c值,但是c多多少少没更到最优。首先还是调和级数预处理,倒序取min。然后考虑到超过\(m\)的也有可能产生更小的代价,因此\(\mathcal{O(n)}\)枚举一遍找到最小的\(j\)使\(i\timesj\gtm\),全部赋......