zoukankan      html  css  js  c++  java
  • 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\) 有十分。

    本欲起身离红尘,奈何影子落人间。
  • 相关阅读:
    【控件推荐】Html编辑器控件 CuteEditor
    【ASP.NET】网页中嵌入视频
    【经验分享】ASP.NET 项目中用到的广告效果
    【转贴好文】服务器概述
    【经验分享】取某月的最后一天的方法
    【经验分享】Word无法使用鼠标选中问题解决
    【经验分享】Sqlserver和Oracle混合事务
    【编码之外】2009春节前最后一天班,感谢一下帮助过我的朋友
    【转贴好文】做快乐的程序员
    【经验分享】JavaScript 中的事件说明
  • 原文地址:https://www.cnblogs.com/jcgf/p/15270175.html
Copyright © 2011-2022 走看看