署训的第一天也是我正式作为成为一名Acmer的第一天。
未来的路还很长,还有很多坎要一步一步跨过去,立个flag:结果不重要,坚持下去就好。
做一下今天的知识点总结
- 加法原理&乘法原理
- 容斥原理
- 概率及数学期望
- (群)置换的一些概念(晕~
下面是一些有趣的题目
A(51 Nod 1383)
题目大意:将一个整数利用二进制性质划分为多个2的幂相加,问有多少种方案。
这是一个基础的计数问题,也是我第一次遇到的所谓计数dp的题。而实际上仔细考虑任何一个方案都可以划分为含有m个2^0和k个2^n(n>0).
显然
奇数时,num[i]=num[i-1]
偶数时,num[i]=num[i-1]+num[i/2] (通过划分为子问题来继续求解)
B Permutations(poj2369)
置换,取最小公倍数即可。
C Invoker (hdu3923)
题目大意:有n个技能,环状手链上有m个装填技能的凹槽,每一种组合方式都可以产生新的技能,且旋转相同或翻转相同的组合情况算作一同种组合,问有多少种技能。
超强的polya(由Burnside引理证明)计数原理:等价类的个数等于所有置换f的C(f)=k^m(f)的平均数(C(f)指对于一个置换f的不动点个数,m(f)指置换f的循环节个数),主要解决染色问题。(训练指南有详解)
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const long long mod=1e9+7;
long long gcd(long long a,long long b)
{
return b==0?a:gcd(b,a%b);
}
long long pow_mod(long long a,long long b)
{
long long s=1;
while(b)
{
if(b&1)
s=(s*a)%mod;
a=(a*a)%mod;
b=b>>1;
}
return s;
}
long long polya(long long m,long long n)
{
long long i,ans=0;
for(i=1;i<=n;i++)
ans+=pow_mod(m,gcd(i,n));
if(n&1)ans+=n*pow_mod(m,n/2+1);
else ans+=n/2*pow_mod(m,n/2)+n/2*pow_mod(m,n/2+1);
ans=ans%mod*pow_mod(2*n,mod-2)%mod;//费马小定理(除法取模不满足结合律)inv(a)=pow(a,p-2)%p
return ans;
}
int main()
{
int T,m,n,k=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
printf("Case #%d: ",k++);
printf("%lld\n",polya(n,m));
}
return 0;
}
注意旋转和翻转均要考虑对称性
旋转:所有循环长度相同,共有gcd(i,n)个循环,则这些置换的不动点总数为
a=
翻转:对n分类讨论
奇,n条对称轴,共(n+1)/2个循环,不动点数b=
偶,有两种对称轴,不动点数b=
D Aeroplane chess(hdu4405)
hhhh做的第一道概率dp(计算期望)
注意这道从后往前推(好像一般都是这样)
代码
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100050
int vis[maxn];
double dp[maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
{
memset(dp,0,sizeof(dp));
memset(vis,-1,sizeof(vis));
for(int i=0;i<m;++i)
{
int a,b;
scanf("%d%d",&a,&b);
vis[a]=b;
}
for(int i=n-1;i>=0;--i)
{
if(vis[i]==-1)
{
for(int j=1;j<=6;j++)
dp[i]+=1.0/6.0*dp[i+j];
dp[i]+=1.0;
}
else
dp[i]=dp[vis[i]];
}
printf("%.4lf\n",dp[0]);
}
return 0;
}
E - 有趣的数列(bzoj1485)
“查”出来的最后一道(疯狂查资料,背结论,相信以后就会明白的~)附hzwer大神详解
卡特兰数直接套结论,记住一个公式 F(n)=C(2*n,n)/(n+1)
代码
#include<iostream>
using namespace std;
unsigned long int binomialCoeff(unsigned int n, unsigned int k)
{
unsigned long int res = 1;
if (k > n - k)
k = n - k;
for (int i = 0; i < k; ++i)
{
res *= (n - i);
res /= (i + 1);
}
return res;
}
unsigned long int catalan(unsigned int n)
{
unsigned long int c = binomialCoeff(2*n, n);
return c/(n+1);
}
int main()
{
int n,p;
cin>>n>>p;
cout << catalan(n)%p <<endl;
return 0;
}
第一天只能水这几道(哇~的一声哭出来
有空再看看讲了的莫比乌斯函数作容斥系数????:同理因子容斥。所有非1的数可以分解成素数的乘积,如果题目能转化成有关纯素数计数的问题,可以用此划分。
还有死活不会求实现的FFT/NTT
毕竟第一天嘛,继续努力!