zoukankan      html  css  js  c++  java
  • 交互题!!!

    今天SDOI二轮培训(没错我又来找虐了)
    D1T1是一道交互题。

    然而我还是太弱。经验也不够。rand检验次数太少。推到推导也不会,遂保龄。

    然而大体思路还是差不多的(剩下的题去一边)

    题面

    Problem A. 排列谜题(perm.c/cpp/pas)

    Input file: N/A

    Output file: N/A

    Time limit: 1 seconds Memory limit: 256 megabytes

    这是一道交互题,本题仅支持 C++。

    小 y 有一个排列 p,小 z 也很想要知道小 y 这个排列到底是什么。
    小 z 只知道这是一个 0 到 n − 1 的排列,下标从 0 开始。小 y 不想告诉小 z 这个排列,于是他规定了小 z 只能向他提出一个固定的问题,小 z 可以向他提出 3 个 0 到 n − 1 中的数字 a, b, c,而小 y 会告诉他 (p^{-1}(x)=(p(a) ∗ p(b) + p(c)))(所有运算都是在 (mod~n) 意义下的)。其中 (p^{-1}(x)) 表示满足 p(y) = x 的 y。由于小 y 没有什么耐心,所以小 z 希望能够尽快得到答案。

    Notes

    下发文件中有 perm.hpp、sample.cpp 两个文件,以下是详细说明,如果懒得看的话你也可以直接参照 sample.cpp 编写代码。

    你需要在你代码的开头 #include ”perm.hpp” 来与交互库交互,你不应该实现 main 函数或试图进行任何文件输入输出,你只需要实现一个函数:std::vector guess(int n),它接受 n,返回一个长度为 n 的 std::vector 表示你猜出的排列。

    你可以使用交互库提供的一个函数:int query_position(int a,int b,int c),这个函数接受 a, b, c,返回 (p^{-1}(x)=(p(a) ∗ p(b) + p(c)))

    样例交互库(下发的 perm.hpp)会从标准输入读入排列。交互库不会占用超过 0.25s 时间和 64MB 内存。

    交互库是固定的,即交互库会在调用你的 guess 函数之前生成好排列,不会动态调整。数据包含若干组数据,你的得分为最小值。

    对于每个数据,假设你的程序没有得出正确的排列或者询问了非法的内容,则获得 0 分。

    否则如果你调用了不超过 12512 次,可以获得 100 分,如果调用了超过 1000000 次,则获得 0 分。否则假设你调用了 (time) 次询问,你的得分将是(frac{1251200}{time})

    //perm.cpp
    #include"perm.hpp"
    #include<bits/stdc++.h>
    
    
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC target("sse4")
    
    #define mms(a,n) memset(a,0,sizeof((a)[0])*(n))
    #define mmp(a,b,n) memcpy(a,b,sizeof((b)[0])*(n))
    #define lowbit(x) ((x)&-(x))
    #define pb push_back
    #define fi first
    #define se second
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define fo(i,l,r) for(register int i=l,_lim_=r;i<=_lim_;i++)
    #define fd(i,r,l) for(register int i=r,_lim_=l;i>=_lim_;i--)
    #define fos(i,l,r,d) for(register int i=l,_lim_=r;i<=r;i+=d)
    #define fol(i,l,r) for(register ll i=l,_lim_=r;i<=_lim_;i++)
    #define fdl(i,r,l) for(register ll i=r,_lim_=l;i>=_lim_;i--)
    #define fosl(i,l,r,d) for(register ll i=l,_lim_=r;i<=r;i+=d)
    #define Clear(a) memset(a,0,sizeof(a))
    #define Copy(a,b) memcpy(a,b,sizeof(b))
    #define ALL(v) v.begin(),v.end()
    #define SZ(v) ((int)v.size())
    #define sqr(x) ((x)*(x))
    #define GCD __gcd
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    
    using namespace std;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    typedef long long ll;
    typedef long double ldb;
    typedef double db;
    typedef pair<int,int> pi;
    typedef vector<int> VI;
    typedef vector<VI> VII;
    
    const int N=5005;
    
    
    
    int n,p[N],nex[N],_0,_n1,_1,v[N][N];
    
    std::vector<int> guess(int n){
    	vector<int> Ans;
    	if(n==1){
    		Ans.push_back(0);
    		return Ans;
    	}
    	
    	memset(v,-1,sizeof(v));
    	fo(i,0,n-1)p[i]=-1;
    	fo(i,0,n-1){
    		bool ok=true;
    		fo(j,0,min(n-1,1000)){
    			if(v[i][j]==-1)v[i][j]=query_position(i,j,j);
    			if(v[i][j]!=j){ok=false;break;}
    		}
    		if(ok){
    			_0=i;
    			break;
    		}
    	}
    	fo(i,0,n-1)if(i!=_0){
    		bool ok=true;
    		fo(j,0,min(n-1,1000)){
    			if(v[i][j]==-1)v[i][j]=query_position(i,j,j);
    			if(v[i][j]!=_0){ok=false;break;}
    		}
    		if(ok){
    			_n1=i;
    			break;
    		}
    	}
    	p[_n1]=n-1;p[_0]=0;
    	_1=query_position(_n1,_n1,_0);
    	p[_1]=1;
    	fo(i,0,n-1)nex[i]=query_position(_1,i,_1);
    	for(int i=_1;i!=_n1;i=nex[i])p[nex[i]]=p[i]+1;
    	for(int i=0;i<n;++i)Ans.push_back(p[i]);
    	return Ans;
    }
    
    //sample
    #include"perm.hpp"
    #include<bits/stdc++.h>
    
    using namespace std;
    
    std::vector<int> guess(int n){
    	vector<int> A;
    	A.push_back(0);
    	if(n==1)return A;
    }
    

    (Solution)

    首先我们从一些具有特殊性质的数字找起:(0~and~1)

    为什么? 首先(0)可以使得返回的数据中的(p(a)p(b))变为(0),直接返回(p(c))的位置

    然后我们找(1),对于查询(pos[1],x,pos[0]),就直接返回(x+1)的位置,利用这个我们可以推出所有的答案。

    然后这个查询次数好像是(3n+)一些错误的查询,据大佬分析,好像是在(15000~6000)之间波动(TQL

    然后就是加速。

    怎么加速呢?首先我们要记录,不能重复查重复的次数。然后我们要重复利用有限的信息。

    如何利用,其实我们大部分的查询都花费在了搜寻(1~and~0)上了。而且这不能重复利用。

    查询(0)时,我们调用的是(query_position(i,j,j)==j)i为当前的下标,j为枚举进行检验的下标

    搜寻(1)时,我们调用的是(query_positon(i,j,pos[0])),i为当前的下标,j为所枚举进行检验i的下标,pos[0]为数值0所在的下标(后同

    但我们似乎却忘了一个问题,这是在模意义下的。

    为什么不搜索-1呢?啥?为什么

    我们查询(-1)时,所调用的是(query_position(i,j,j)==pos[0]),可以看出,是和查询(0)时的参数是一样的。在加上记忆,差不多就能剩下许多的查询

    然后因为有特殊情况,需要多次判断,这里没听懂,听说是(2sqrt{n})

    然后因为我太菜了。没有标程,大佬的厚不下脸皮来贴,就不贴了233

  • 相关阅读:
    pdf在线转换器
    抖音修复老照片动起来笑起来的程序app的下载地址
    FFmpeg.AutoGen Unable to load DLL 'avutil.56' 解决方法
    Array.prototype.fill 填充值被复用的问题
    Recoil Input 光标位置被重置到末尾的问题
    TypeScript 扩展全局 Window 时报错的解决
    Recoil 中默认值的正确处理
    Recoil 中多级数据联动及数据重置的合理做法
    Recoil 默认值及数据级联的使用
    Recoil 的使用
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9251145.html
Copyright © 2011-2022 走看看