昼夜切换动画

2021.09.14 膜你赛

2021.09.14 膜你赛

T1

Description

给定一个 \(1 \sim n\) 的排列 \(a_i\) 给出 \(q\) 个询问 \((x,m)\) 他想知道:

\[\underbrace{a[a[a[…a[x]…]]]}_{m 个 a} \]

的值是多少

Solution

考试的时候写的 \(n^2\) 的做法。

对于每一个点能跳到的下一个点,我们连一条边,最后序列上一定是一个个环的形式,

暴力找到循环节,输出答案,就是输入有些毒瘤。

Code

/*
* @Author: smyslenny
* @Date:    2021.09.14
* @Title:   
* @Main idea:
*复杂度:O(n^2) 能过50 
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>

#define ll long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=998244353;
const int M=1e+5;
int n,Q,x,m;
int read()
{
	int x=0,y=1;
	char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
int mp[M],ord[M];
struct que{ int x,m;}q[M];
struct ed{int u,v,net;} edge[M];
int head[M],num,vis[M],pa[M];
void addedge(int u,int v) { edge[++num].u=u;edge[num].v=v;edge[num].net=head[u];head[u]=num;}
int solve(int x,int m)
{
	memset(pa,0,sizeof(pa));
	memset(vis,0,sizeof(vis));
	for(int i=0;i<m;i++)
	{
		if(vis[x]==0) 
		{
			vis[x]=1;
			pa[i]=x;
			x=head[x];
			x=edge[x].v;
		}
		else
		{
			m%=(i);		
			return pa[m];
			break;
		}
	}
	return x;
}
int main()
{
//	freopen("kengdie.in","r",stdin);
//	freopen("kengdie.out","w",stdout);
	while(1)
	{
		x=read();
		if(mp[x]==0)
		{
			ord[++n]=x;
			mp[x]=1;
		}
		else 
		{
			m=read();
//			if(m>n) m%=n;
			break;
		}
	}
	num=0;
	for(int i=1;i<=n;i++)
		addedge(i,ord[i]);
	printf("%d\n",solve(x,m));
	while(scanf("%d%d",&x,&m)!=EOF)
	{
//		if(m>n) m%=n;
		printf("%d\n",solve(x,m));
	}
	return 0;
}
/*
3
2
1
1
1
2
2
*/

T2

Descrition

给定 \(n\) 个数 \(a_i\) 找到一个子集 \(b_i\) 最大化

\[\sum_{i = 1}^{|b|}b_i \bmod M \]

Solution

看到数据范围果断折半搜索。

上次考试碰到折半搜索写的 dp,这次直接搜索,再合并左右区间就行了。

Code

/*
* @Author: smyslenny
* @Date:    2021.09.
* @Title:   
* @Main idea:
* 复杂度 O(2^n) 50分 
* O(1e6) 
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>

#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int M=(1<<21);
int n,mod,mp[M];
int read()
{
	int x=0,y=1;
	char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
namespace substack1{
	
	int las=0,js=0,Ans=-INF,sz[M];
	void dfs(int x)
	{
		if(x>n) return;
		sz[x]=js;
		js+=mp[x];
		js%=mod;
		Ans=max(Ans,js);
		dfs(x+1);
		js=sz[x];
		dfs(x+1);
		return;
	}
	void main()
	{
		dfs(1);
		if(Ans==-INF) printf("0\n"); 
		else printf("%d\n",Ans);
	}
}

namespace substack2{
	int num=0,Ans=0;
	void main()
	{
		for(int i=1;i<=n;i++)
			num+=mp[i],num%=mod,Ans=max(Ans,num);
		printf("%d\n",Ans);	
	}
}
namespace substack3{

	int sum_1[M],sum_2[M],js_1,js_2,mid,Ans=-INF;
	void dfs_1(int x,int num)
	{
		sum_1[js_1++]=num%mod;
		for(int i=x;i>mid;i--)
			dfs_1(i-1,(num+mp[i])%mod);
	}
	void dfs_2(int x,int num)
	{
		sum_2[js_2++]=num;
		for(int i=x;i>=1;i--)
			dfs_2(i-1,(num+mp[i])%mod);
	}
	void main()
	{
		mid=n>>1;
		sort(mp+1,mp+1+n);
		dfs_1(n,0);
		dfs_2(mid,0);
		sort(sum_1,sum_1+js_1);
	 	for(int i=0;i<js_2;i++)
	 	{
	 		int l=0,r=js_1;
	 		while(l<=r)
	 		{
	 			int mid=(l+r)>>1;
	 			if(sum_1[mid]>mod-sum_2[i])
					r=mid-1;
	 			else 
					l=mid+1,Ans=max(Ans,(sum_2[i]+sum_1[mid])%mod);
			}
		} 		
		printf("%lld\n",Ans);
	}
}
signed main()
{
	freopen("gift.in","r",stdin);
	freopen("gift.out","w",stdout); 
	n=read(),mod=read(); 
	for(int i=1;i<=n;i++)
		mp[i]=read(),mp[i]%=mod;
//	if(n<=16) substack1::main();
//	substack2::main();//以为理解错题意了,结果发现没理解错题意
//	else 
		substack3::main(); 
	return 0;
}

T3

Description

给定 \(n\) 个数 \(a_i\) 和另外的两个数 \(A, B\) 有两种操作:

  1. 执行 \(A = A - 1\)

  2. 选择一个 \(1\)\(n\) 之间的数 \(x\) 执行: \(A = A - (A \bmod a_x)\)

求最少的操作次数使 \(A = B\)

Solution

不大会,但是直接输出 \(A-B\) 有十分。

posted @ 2021-09-14 23:06  smyslenny  阅读(149)  评论(0编辑  收藏  举报