ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[POI2008]PER

2021-04-24 21:32:48  阅读:222  来源: 互联网

标签:ch return POI2008 int void PER xin inline


很有思维的一道题

这个题的题面非常简单,出题人很友好,没有搞什么奇怪的背景,(卡农(P3214)的作者看看人家),所以理解题面就是:

一句话题意:

给定一个长度为 \(n\) 的数列,求这个数列是在其全排列中的排名是多少,输出排名 \(mod\) \(m\) 的结果。

赵小兵同学:这不就是个康托展开嘛,看我A掉这个大水题。

于是,他打出了下面这个程序:


#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x7f7f7f7f7f
const int one = 1e7+10;
inline void openfile()
{freopen("t.txt","r",stdin);}
namespace zxb
{
	int tree[1000005];
	int n;
	inline int lowbit(int x)
	{
		return x&-x;
	}
	inline void update(int x,int y)
	{
		while(x<=n){
			tree[x]+=y;
			x+=lowbit(x);
		}
	}
	inline int query(int x)
	{
		int sum=0;
		while(x)
		{
			sum+=tree[x];
			x-=lowbit(x);
		}
		return sum;
	}
	int mod;
	int jc[1000005];
	int a[1000005];
	inline short main()
	{
		//openfile();
		jc[0] = jc[1] = 1;
		cin >> n >> mod;
		for(int i=1;i<=n;i++)
		{
			jc[i]=(jc[i-1]*i)%mod;
			update(i,1);
		}
		int ans = 0;
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			ans=(ans+((query(a[i])-1)*jc[n-i]) % mod) % mod;
			update(a[i],-1);
		}
		cout<<ans +1<<endl;
	   	return 0;
	  }
}
signed main() { return zxb::main();}

然后。。。
赵小兵同学翻车记录

旁边的 \(C\) 君看不下去了,转眼就打了一个暴力算法,并对赵小兵同学发来了鄙视

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x7f7f7f7f7f
const int one = 1e7+10;
inline void openfile()
{freopen("t.txt","r",stdin);}
inline int get()
{
	int s = 0,f = 1;
	register char ch = getchar();
	while(!isdigit(ch))
	{
		if(ch == '-') f= -1;
		ch = getchar();
	}
	while(isdigit(ch))
	{
		s = s* 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
namespace xin
{
	int a[one],b[one];
	int mod,n;
	inline bool comp()
	{
		for(register int i=1;i<=n;++i)
			if(a[i] != b[i])
				return false;
		return true;
	}
	inline short main()
	{
	//	openfile();
		n = get(); mod = get();
		for(register int i=1;i<=n;++i) a[i] = get(),b[i] = a[i];
		sort(a+1,a+1+n);
		int cnt = 1;
		while(next_permutation(a+1,a+n+1))
		{
			cnt++;
			if(comp() == 1) 
			{
				cout<<cnt % mod<<endl;
				return 0;
			}
		}
		return 0;
	}
}
signed main() { return xin::main();}

\(C\) 君的暴力记录\(C\) 君的暴力记录
\(C\) 君整整比赵小兵同学多了一倍的分数,这时候,坐在一旁的 \(XIN\) 同学看不下去了,但 \(XIN\) 同学一时间也无法想出正解,但是经过 \(XIN\) 同学为期 \(3\) 天的不懈奋斗,终于 \(A\) 掉了这个题目:
赵小冰和 \(C\) 君都想要知道他的思路, \(XIN\) 同学开始讲到:

首先,要考虑每一个数位的贡献值,其实赵小兵同学的第一想法是不错的,但是只能说是不对,因为这个题目存在重复,也存在模数为合数的时候,所以康托展开就不管用了,所以要考虑别的想法,发现全排列就和本身的字典序有关,之后得出计算式:

\[w \cdot \frac{(n-i)!}{\Pi \ {cnt[j]!}} \]

$cnt $ 就是从 \(i\) 到 $n $ 中 \(j\) 所出现的个数

但是问题就又来了,合数应该怎么处理呢???

最先考虑费马小定理:

\[a^{p-1}≡1 (mod\ p) \]

可是,模数为合数啊,所以考虑扩展欧几里的求出逆元:

inline void exgcd(int a,int b,int &x,int &y)
{
   if(!b) { x = 1; y = 0; return;}
   exgcd(b,a%b,y,x);
   y -= a / b * x;
}
inline int get_inv(int x,int p)
{
   int a,b;
   exgcd(x,p,a,b);
   return (a % p + p) % p;
}

之后可以用树状数组在 \(log\) 的时间复杂度的情况下求出区间最小值:

namespace xin_bit
{
   int s[maxn];
   inline int lowbit(int x)
   {return x & -x;}
   inline void add(int x,int val)
   {
       while(x <= maxn)
       {
           s[x] += val;
           x += lowbit(x);
       }
   }
   inline int query(int x)
   {
       register int ret = 0;
       while(x)
       {
           ret += s[x];
           x -= lowbit(x);
       }
       return ret;
   }
}

之后来一点小小的转移,将因子分解,之后再合并,最后就可以按照计算式求出本题的答案了。

慷慨的 \(XIN\) 还放出了代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6+10;
namespace xin_io
{
   inline int get()
   {
       int s =0 ,f = 1;
       register char ch = getchar();
       while(!isdigit(ch))
       {
           if(ch == '-') f= -1;
           ch = getchar();
       }   
       while(isdigit(ch))
       {
           s = s *10 + ch - '0';
           ch = getchar();
       }
       return s * f;
   }
   inline void write(int x)
   {
       if(x < 0) putchar('-'),x = -x;
       if(x > 9) write(x/10);
       putchar(x % 10 + '0');
   }
}
using xin_io::get; using xin_io::write;
inline void openfile()
{freopen("t.txt","r",stdin);}
namespace xin_bit
{
   int s[maxn];
   inline int lowbit(int x)
   {return x & -x;}
   inline void add(int x,int val)
   {
       while(x <= maxn)
       {
           s[x] += val;
           x += lowbit(x);
       }
   }
   inline int query(int x)
   {
       register int ret = 0;
       while(x)
       {
           ret += s[x];
           x -= lowbit(x);
       }
       return ret;
   }
}
namespace xin
{
   #define m(c) cout<<sizeof(c) / (1 << 20) << "MB"<<endl
   #define min(a,b) (a) < (b) ? (a) : (b)
   #define max(a,b) (a) > (b) ? (a) : (b)
   int mod;
   int n,m;
   bool number[maxn];
   int prime[maxn];
   int i,j,count=0;
   inline void xin_shai(int N)
   {
       memset(number,true,sizeof(number));
       for(i=2;i<=N;i++)
       {
           if(number[i])
               prime[count++]=i;
           for(j=0;j<count and prime[j]*i<=N;j++)
           {
               number[prime[j]*i]=false;
               if(i%prime[j]==0)
                   break;
           }
       }
   }
   inline void exgcd(int a,int b,int &x,int &y)
   {
       if(!b) { x = 1; y = 0; return;}
       exgcd(b,a%b,y,x);
       y -= a / b * x;
   }
   inline int get_inv(int x,int p)
   {
       int a,b;
       exgcd(x,p,a,b);
       return (a % p + p) % p;
   }
   int cnt[110],link[110][maxn];
   int rec1[maxn],rec2[maxn];
   int temp,a[maxn],fac[maxn],num_fac = 0;
   inline void cont(int &x,int val)
   {
       for(register int i=1;i<=num_fac;++i)
       {
           register int zhuan = fac[i];
           while(!(x % zhuan))
               x/=zhuan,cnt[i] += val;
       }
   }
   inline int get_num()
   {
       int ret = 1;
       for(register int i=1;i<=num_fac;++i)
           ret = (ret * link[i][min(rec2[i],cnt[i])] ) % m;
       return ret;
   }
   inline int work()
   {
       int ans = 0,ret = 1;
       rec1[a[n]] = 1; xin_bit::add(a[n],1);
       for(register int i=n-1;i>=1;--i)
       {
           int zhuan  = n - i;
           cont(zhuan,1);
           ret *= zhuan; ret %= m;
           zhuan = ++rec1[a[i]];
           cont(zhuan,-1);
           ret = (ret * get_inv(zhuan,m) + m) % m;
           xin_bit::add(a[i],1);
           zhuan = get_num();
           ans += (ret % m * xin_bit::query(a[i] - 1) % m * zhuan % m + m ) % m;
           ans %= m;
       }
       return ++ans;
   }
   inline short main()
   {
       openfile();
       n = get(); m = get(); temp = m;
       for(register int i=1;i<=n;++i) a[i] = get();
       for(register int i=2;i<=sqrt(temp);++i)
       if(temp % i == 0)
       {
           fac[++num_fac] = i;
           link[num_fac][0] = 1;
           for(register int j=1;j<=maxn;++j)
               link[num_fac][j] = link[num_fac][j-1] * i % m,rec2[num_fac] ++;
           while(temp % i == 0)temp /= i;
       }
       if(temp > 1)
       {
           fac[++num_fac] = temp;
           link[num_fac][0] = 1;
           for(register int j=1;j<=maxn;++j)
               link[num_fac][j] = link[num_fac][j-1] * temp % m,rec2[num_fac]++;
       }
       int ans = work() % m;
       write(ans);
       putchar('\n');
       return 0;
   } 
}
signed main() {return xin::main();}

标签:ch,return,POI2008,int,void,PER,xin,inline
来源: https://www.cnblogs.com/NP2Z/p/14698168.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有