https://ac.nowcoder.com/acm/contest/881#question
https://blog.csdn.net/ftx456789/article/details/96451366?tdsourcetag=s_pctim_aiomsg
求解
1 π ∫ 0 ∞ 1 ∏ i = 1 n ( a i 2 + x 2 ) d x \frac 1\pi \int _0^∞{\frac1{\prod_{i=1}^n{(a_i^2+x^2)}}}dx π1∫0∞∏i=1n(ai2+x2)1dx
将 1 ∏ i = 1 n ( a i 2 + x 2 ) \frac 1{\prod_{i=1}^n{(a_i^2+x^2)}} ∏i=1n(ai2+x2)1裂项为 c 1 a 1 2 + x 2 + c 2 a 2 2 + x 2 . . . . . . \frac {c1}{a_1^2+x^2}+\frac {c2}{a_2^2+x^2}...... a12+x2c1+a22+x2c2......
求解当n=1,n=2情况下c的值,可以找出规律
即 c i = 1 ∏ i = 1 n ( a j 2 − a i 2 ) ( 1 ≤ j ≤ n 且 j ! = i ) c_i=\frac {1}{\prod _{i=1}^{n}{(a_j^2-a_i^2)}}(1\leq j \leq n 且j!=i) ci=∏i=1n(aj2−ai2)1(1≤j≤n且j!=i)
再根据积分公式 ∫ 0 ∞ 1 a 2 + x 2 d x = π 2 a \int_0^∞ \frac 1 {a^2+x^2}dx=\frac \pi {2a} ∫0∞a2+x21dx=2aπ
即可求解
注意!
计算减法的时候一定要记得+mod
#include
using namespace std;
typedef long long int ll;
const int maxn = 1e5+10;
const ll mod=1e9+7;
ll inverse(ll a)
{
return a == 1 ? 1 : 1LL * (mod - mod / a) * inverse(mod % a) % mod;
}
ll a[maxn];
int main() {
int n;
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
ll ans=0;
for(int i=1;i<=n;i++)
{
ll fz=1;
ll fm=1;
for(int j=1;j<=n;j++)
{
if(j!=i)
{
fm=(fm*(a[j]*a[j]%mod-a[i]*a[i]%mod+mod))%mod;
}
}
fm=fm*a[i]%mod*2%mod;
ans=(ans+inverse(fm))%mod;
}
//ans=ans*inverse(2)%mod;
printf("%lld\n",ans);
}
return 0;
}
给n和m,求所有由n个AB和m个BA作为子序列构成的串有多少个,结果mod 1 0 9 + 7 10^9+7 109+7
先假设已经放了n个A,那么下一个放的必须是B,否则无法构成想要的串。
那么由此可知,当A的数量少于n个的时候可以随意放A,因为这些A是必须的,但是一旦当A超过了n,就必须要考虑此时B的数量。
再假设若已经放了n个A和一个B,那么接下来至多只能放一个A,然后就得放B。
因此可以知道 当i-n<=j时可以放A
B同理
根据这样的条件可以写出dp转移方程
d p [ i + 1 ] [ j ] = d p [ i + 1 ] [ j ] + d p [ i ] [ j ] ( i + 1 − n ≤ j ) dp[i+1][j]=dp[i+1][j]+dp[i][j] (i+1-n\leq j) dp[i+1][j]=dp[i+1][j]+dp[i][j](i+1−n≤j)
d p [ i ] [ j + 1 ] = d p [ i ] [ j + 1 ] + d p [ i ] [ j ] ( j + 1 − m ≤ i ) dp[i][j+1]=dp[i][j+1]+dp[i][j](j+1-m\leq i) dp[i][j+1]=dp[i][j+1]+dp[i][j](j+1−m≤i)
另外用memset会超时,只能for循环
#include
using namespace std;
typedef long long int ll;
const int maxn = 2e3+100;
const ll mod=1e9+7;
ll dp[maxn][maxn];
int main()
{
int n,m;
while(cin>>n>>m)
{
for(int i=0;i<=n+m;i++)
{
for(int j=0;j<=n+m;j++)
{
dp[i][j]=0;
}
}
dp[0][0]=1;
for(int i=0;i<=n+m;i++)
{
for(int j=0;j<=n+m;j++)
{
if(i+1-n<=j)
dp[i+1][j]=(dp[i+1][j]+dp[i][j])%mod;
if(j+1-m<=i)
dp[i][j+1]=(dp[i][j+1]+dp[i][j])%mod;
}
}
printf("%lld\n",dp[n+m][n+m]);
}
return 0;
}
求n个元素中,异或和为0的子集大小之和
https://www.cnblogs.com/Yinku/p/11212303.html
首先求所有元素的线性基B,其秩为r,由于剩下的数构成的子集的异或和总能在线性基里找到唯一对应,那么我们很容易知道所有异或和为0的子集个数为 2 n − r 2^{n-r} 2n−r,那么要求这些子集的大小之和就需要去求出每一个数的贡献。
①对于未插入线性基的(n-r)个数来说,每一个数所能构成的子集个数为 2 n − r − 1 2^{n-r-1} 2n−r−1
那么这个数的贡献就为 2 n − r − 1 2^{n-r-1} 2n−r−1,那么这(n-r)个数的总贡献就为 ( n − r ) 2 n − r − 1 (n-r)2^{n-r-1} (n−r)2n−r−1
②再考虑插入线性基的r个数,每一个数的贡献为他在①中被使用的次数。要求他被使用的次数,需要将除他以外的(n-1)个数求线性基B2,再将他插入B2,若插入成功,则证明B2不存在组合与他异或和为0,那么他也就没有贡献。若插入失败,则他的贡献为 2 n − r − 1 2^{n-r-1} 2n−r−1,因为B2的秩必定也为r。
剩下的就是优化问题,在构造B的时候,将无法插入B的数插入到B1中。那么在②构造B2时,先复制B1,然后再将其他数插入,这样就快了很多。
#include
#include
#include
using namespace std;
typedef long long int ll;
const int maxn = 1e5+100;
const ll mod=1e9+7;
const int N=63;
struct LinearBase{
ll base[maxn]; //线性基
int cnt; //插入的元素个数
void init()
{
memset(base,0,sizeof(base));
cnt=0;
}
void copy(LinearBase a)
{
cnt=a.cnt;
memcpy(base,a.base,sizeof(base));
}
bool insert(ll x)
{
for (int j = N; ~j; --j) //N为最大位数
{
if (((x >> j) & 1))
{
if (base[j]) x ^= base[j];
else
{
base[j] = x;
cnt++;
return true;
}
}
}
return false;
}
}B,B1,B2;
ll a[maxn];
bool vis[maxn];
void ini()
{
B.init();
B1.init();
B2.init();
memset(vis,0,sizeof(vis));
}
ll qmod(ll a,ll b){
ll c=1;
while(b)
{
if(b&1)
{
c=c*a%mod;
}
a=a*a%mod;
b>>=1;
}
return c%mod;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
ini();
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(B.insert(a[i]))
{
vis[i]=1;
}
else
{
B1.insert(a[i]);
}
}
ll ans=0;
ll p2=0;
if(n!=B.cnt){
p2=qmod(2,(n-B.cnt-1))%mod;
ans=p2*(n-B.cnt)%mod;
}
for(int i=1;i<=n;i++)
{
if(vis[i])
{
B2.copy(B1);
for(int j=1;j<=n;j++)
{
if(i!=j&&vis[j])
{
B2.insert(a[j]);
}
}
if(!B2.insert(a[i]))
{
ans=(ans+p2)%mod;
}
}
}
printf("%lld\n",ans);
}
}