C. Scoring Subsequences
思路
只要看出所需要维护的长度一定是越来越长的就行,且每次只能+0 或者+1。所以每次只需要判断一下。
注意不用维护具体的分数,可能这个值会很大,导致爆掉
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#define fir(i,a,b) for(int i=a;i<b;i++)
#define dug cout<<"ceshi"<<endl;
typedef long long LL;
#define met(x,y) memset(x,y,sizeof x)
//#define read(x) scanf("%d",&x)
using namespace std;
typedef pair<int,int> PII;
const int N=1e5+10;
LL ss,xx;
int si=0;
LL a[N];
inline int read()
{
char c = getchar();int x = 0,s = 1;
while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}//是符号
while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}//是数字
return x*s;
}
bool cal (LL x,LL y,LL a,LL b)
{
//cout<<x<<" "<<y<<" "<<a<<" "<<b;
return x*b>=y*a;
}
int main()
{
//freopen("test.txt", "r", stdin);
int t=read();
while(t--)
{
int n;
cin>>n;
si=1;
cout<<1<<" ";
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=2;i<=n;i++)
{
if(cal(a[i],si+1,a[i],a[i-si]))si++;
cout<<si<<" ";
}
puts("");
}
//freopen("CON", "r", stdin);
//system("pause");
return 0;
}
D - Counting Factorizations
思路
首先必须要清楚几个点
- 质数的种类一定要大于等于n
- 在每一种方案中的底数中,每种质数只能出现一次
那么可以设一个c数组来存储每一种质数出现的次数,b数组来存储每一种非质数出现的次数
那么在每一次确定底数之后,如果该质数为底数就在c数组中减一
最终在这个底数方案中所有的答案为
n
!
b
1
!
∗
b
2
!
∗
.
.
.
∗
b
k
!
∗
c
1
!
∗
.
.
.
∗
c
k
!
\frac{n!}{b_1!*b_2!*...*b_k!*c_1!*...*c_k!}
b1!∗b2!∗...∗bk!∗c1!∗...∗ck!n!,就是一个含有相同元素的全排列问题
可以看出其实
n
!
b
1
!
∗
b
2
!
∗
.
.
.
∗
b
k
!
\frac{n!}{b_1!*b_2!*...*b_k!}
b1!∗b2!∗...∗bk!n!其实是不变的,只要求所有的
1
c
1
!
∗
.
.
.
∗
c
k
!
\frac{1}{c_1!*...*c_k!}
c1!∗...∗ck!1和就行。到这应该能看出应该是用dp求所有的
1
c
1
!
∗
.
.
.
∗
c
k
!
\frac{1}{c_1!*...*c_k!}
c1!∗...∗ck!1和了,O(
n
2
n^2
n2)的复杂度完全可以。
设f[i][j]的状态表示为,在前i个数中,选了j个数为底数的和
那么
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
−
1
]
∗
1
(
c
i
−
1
)
!
+
f
[
i
−
1
]
[
j
]
∗
1
(
c
i
−
1
)
!
f[i][j]=f[i-1][j-1]*\frac{1}{(c_i-1)!}+f[i-1][j]*\frac{1}{(c_i-1)!}
f[i][j]=f[i−1][j−1]∗(ci−1)!1+f[i−1][j]∗(ci−1)!1
具体细节就看代码了
代码
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1e6+10,M=5100,Q=998244353;
long long f[M][M];
bool is_prime[N];//该数是不是质数
int prime[N],idx=0;
int prime_si[N],notprime_si[N];
vector<int> list_prime,notlist_prime;
int n;
long long fast[M],fast_inv[M];//阶乘和,阶乘和的逆
int qmi(long long x,int k)//快速幂
{
long long res=1;
while(k)
{
if(k&1)res=res*x%Q;
x=x*x%Q;
k>>=1;
}
return res;
}
void init()//筛质数
{
is_prime[1]=true;
for(int i=2;i<=(N-1);i++)
{
if(!is_prime[i])prime[idx++]=i;
for(int j=0;prime[j]<=(N-1)/i;j++)
{
is_prime[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
fast[0]=1;
for(int i=1;i<M;i++)fast[i]=fast[i-1]*i%Q;
for(int i=0;i<M;i++)fast_inv[i]=qmi(fast[i],Q-2);
}
bool check(int i,int j)
{
if(i<j)return false;
if(n-j>=list_prime.size()-i)return false;
return true;
}
int main()
{
init();
cin>>n;
list_prime.push_back(0);
for(int i=1;i<=2*n;i++)
{
int tem;
cin>>tem;
if(is_prime[tem])
{
//cout<<tem;
if(notprime_si[tem]==0)notlist_prime.push_back(tem);
notprime_si[tem]++;;
}
else
{
if(prime_si[tem]==0)list_prime.push_back(tem);
prime_si[tem]++;
}
}
f[0][0]=1;
for(int i=1;i<list_prime.size();i++)
{
int tem=list_prime[i];
for(int j=0;j<=n&&i>=j;j++)
{
if(check(i-1,j-1))f[i][j]=f[i-1][j-1]*fast_inv[prime_si[tem]-1]%Q;
if(check(i-1,j))f[i][j]=(f[i][j]+f[i-1][j]*fast_inv[prime_si[tem]]%Q)%Q;
}
}
long long res=f[list_prime.size()-1][n];
for(auto ch:notlist_prime)
{
res=(res*fast_inv[notprime_si[ch]])%Q;
}
res=res*fast[n]%Q;
cout<<res;
return 0;
}
痛苦的回忆
线性筛的话,两个循环一定是大于等于,不能是等于,不然会漏筛
但是我用了很多次都没出现这样的情况,所以调的半天代码,一直以为是dp那出错了可恶
错误的代码
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1e6+10,M=5100,Q=998244353;
long long f[M][M];
bool is_prime[N];
int prime[N],idx=0;
int prime_si[N],notprime_si[N];
vector<int> list_prime,notlist_prime;
int n;
long long fast[M],fast_inv[M];
int qmi(long long x,int k)
{
long long res=1;
while(k)
{
if(k&1)res=res*x%Q;
x=x*x%Q;
k>>=1;
}
return res;
}
void init()//筛质数
{
is_prime[1]=true;
for(int i=2;i<N;i++)
{
if(!is_prime[i])prime[idx++]=i;
for(int j=0;prime[j]<N/i;j++)
{
is_prime[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
fast[0]=1;
for(int i=1;i<M;i++)fast[i]=fast[i-1]*i%Q;
for(int i=0;i<M;i++)fast_inv[i]=qmi(fast[i],Q-2);
}
bool check(int i,int j)
{
if(i<j)return false;
if(n-j>=list_prime.size()-i)return false;
return true;
}
int main()
{
init();
cin>>n;
list_prime.push_back(0);
for(int i=1;i<=2*n;i++)
{
int tem;
cin>>tem;
if(is_prime[tem])
{
//cout<<tem;
if(notprime_si[tem]==0)notlist_prime.push_back(tem);
notprime_si[tem]++;;
}
else
{
if(prime_si[tem]==0)list_prime.push_back(tem);
prime_si[tem]++;
}
}
f[0][0]=1;
for(int i=1;i<list_prime.size();i++)
{
int tem=list_prime[i];
for(int j=0;j<=n&&i>=j;j++)
{
if(check(i-1,j-1))f[i][j]=f[i-1][j-1]*fast_inv[prime_si[tem]-1]%Q;
if(check(i-1,j))f[i][j]=(f[i][j]+f[i-1][j]*fast_inv[prime_si[tem]]%Q)%Q;
}
}
long long res=f[list_prime.size()-1][n];
for(auto ch:notlist_prime)
{
res=(res*fast_inv[notprime_si[ch]])%Q;
}
res=res*fast[n]%Q;
cout<<res;
return 0;
}