用于博主过于菜鸡,不会E,所以只能讲A,B,C,D,F了
A,B好像大家都会,就不讲了
C:n个数记为k1k_1k1 ~knk_nkn,那么可以成功实现当且仅当:
{∑i=1nki=3∗mki∈[0,2∗m]奇数的个数小于等于m且与m模2同余\left\{\begin{matrix}
\sum_{i=1}^{n}k_i=3*m\\
k_i\in[0,2*m]\\
奇数的个数小于等于m且与m模2同余
\end{matrix}\right.⎩⎨⎧∑i=1nki=3∗mki∈[0,2∗m]奇数的个数小于等于m且与m模2同余
于是稍微容斥和组合数一下即可
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int Mod=998244353;
int n,m;
#define Maxn 3000010
int fact[Maxn],inv[Maxn];
inline int C(int i,int j){return 1ll*fact[i]*inv[i-j]%Mod*inv[j]%Mod;}
inline int calc(int x){return C(x+n-1,n-1);}
int main(){
scanf("%d%d",&n,&m);
fact[0]=1;
for(register int i=1;i<=3000000;++i)fact[i]=1ll*fact[i-1]*i%Mod;
inv[0]=inv[1]=1;
for(register int i=2;i<=3000000;++i)
inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
for(register int i=2;i<=3000000;++i)inv[i]=1ll*inv[i-1]*inv[i]%Mod;
int Ans=0;
for(register int i=0;i<=min(m,n);++i)
if((m-i)%2==0){
int at=(3*m-i)/2;
int res=calc(at);
res=(res-1ll*i*C(at-m+n-1,n-1)%Mod+Mod)%Mod;
if(at>m)res=(res-1ll*(n-i)*C(at-m+n-2,n-1)%Mod+Mod)%Mod;
res=1ll*res*C(n,i)%Mod;
Ans=(Ans+res)%Mod;
}
printf("%d\n",Ans);
return 0;
}
D:
题意:n个点,如果i<j,i->j有一条-1的边
如果i>j,i->j有一条1的边
以上两种边可删,且删除有一定代价(非负)
i->i+1恒有一条长度为0的边,不可删除
问最少多少代价删边可以使得图中不存在负环
解法:这是一道神题
考虑一张图不存在负环的等价条件,便是可以为这张图的每个点安排一个点权qiq_iqi
使得对于任意一条边(u,v,w),有qu+w≥qvq_u+w\geq q_vqu+w≥qv
证明:若无负环,每个点有最短路,q取最短路即可
若有q,那么对于一个环中的每条边,变形得w≥qv−quw\geq q_v-q_uw≥qv−qu
右边的和为0,于是肯定非负
于是考虑确定一个序列q,并以此确定此时的最小代价
由于i到i+1总有一条为0的边
故我们有qi≥qi+1q_i\geq q_{i+1}qi≥qi+1
不妨令pi=qi−qi+1p_i=q_i-q_{i+1}pi=qi−qi+1,则pi非负p_i非负pi非负
i->j为-1的边在图中,需满足∑k=ij−1pk≥1\sum_{k=i}^{j-1}p_k\geq1∑k=ij−1pk≥1
i->j为1的边在图中,需满足∑k=ji−1pk≤1\sum_{k=j}^{i-1}p_k\leq 1∑k=ji−1pk≤1
于是dp一下即可O(n3)O(n^3)O(n3)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
#define Maxn 505
ll val1[Maxn][Maxn];//below
ll val2[Maxn][Maxn];//up
ll f[Maxn][Maxn];
ll sum[Maxn];
inline int calc(int x){return x*(x+1)/2;}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
ll All=0;
rd(n);
int x;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
if(j!=i){
rd(x);
All+=x;
if(j<i)val1[j][i-1]=x;
else val2[i][j-1]=x;
}
n--;
for(register int i=1;i<=n;++i)
for(register int j=2;j<=i;++j){
val1[j][i]+=val1[j-1][i];
val2[j][i]+=val2[j-1][i];
}
ll Ans=0;
ll Ha=0;
for(register int i=1;i<=n;++i){
Ha+=val1[i][i];
f[i][0]=Ha+val2[i][i];
for(register int j=0;j<i;++j){
ll tmp=0;
for(register int k=i+1;k<=n;++k){
f[k][i]=max(f[k][i],f[i][j]+tmp+val1[k][k]-val1[i][k]+val2[k][k]);
tmp+=val1[k][k]-val1[j][k]+val2[i][k];
}
}
}
for(register int i=1;i<=n;++i)sum[i]=val1[i][i]+sum[i-1];
for(register int i=1;i<=n;++i)
for(register int j=i+1;j<=n;++j){
val1[i][j]+=val1[i][j-1];
val2[i][j]+=val2[i][j-1];
}
for(register int i=1;i<=n;++i)
for(register int j=0;j<i;++j)
Ans=max(Ans,f[i][j]-val1[j][n]+val1[j][i]+val2[i][n]-val2[i][i]+sum[n]-sum[i]);
printf("%lld\n",All-Ans);
return 0;
}
F
题意:有多少种排列p,值域为[0,2∗n)[0,2*n)[0,2∗n),满足对于任意i,n2≤i2+pi2≤4∗n2n^2\leq i^2+p_i^2\leq 4*n^2n2≤i2+pi2≤4∗n2
解法:对于每个i确定上下界,考虑容斥
容斥至少k个在下界内的
至于如何求方案数,博主不想写了,去看官方题解吧。
总之,第一步容斥是关键,后面的处理也很巧妙
agc杀死我
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,Mod;
#define Maxn 605
int dp[Maxn][Maxn];
int g[Maxn];
struct Data{
int val,id;
bool operator <(const Data &z)const{return val==z.val?id>z.id:val<z.val;}
}seq[Maxn<<1];
int calc(int K){
int tmp=0;
dp[0][0]=1;
for(register int i=1;i<=2*n;++i){
if(seq[i].id>=n)tmp++;
for(register int j=0;j<=i-tmp;++j){
if(seq[i].id>=n)dp[i][j]=1ll*dp[i-1][j]*(seq[i].val-j-tmp+2+Mod)%Mod;
else{
dp[i][j]=0;
if(j!=i-tmp)dp[i][j]=(dp[i][j]+1ll*dp[i-1][j]*(g[seq[i].id]-n-K-i+tmp+j+2+Mod))%Mod;
if(j)dp[i][j]=(dp[i][j]+1ll*dp[i-1][j-1]*(seq[i].val-j-tmp+2))%Mod;
}
}
}
return dp[2*n][K];
}
int main(){
scanf("%d%d",&n,&Mod);
for(register int i=0;i<n;++i){
seq[i+1]=(Data){floor(sqrt(n*n-i*i-1)),i};
g[i]=floor(sqrt(4*n*n-i*i));
if(i==0)g[i]=2*n-1;
}
for(register int i=n;i<2*n;++i)seq[i+1]=(Data){floor(sqrt(4*n*n-i*i)),i};
sort(seq+1,seq+2*n+1);
int Ans=0;
for(register int i=0;i<=n;++i){
if(i&1)Ans=(Ans-calc(i)+Mod)%Mod;
else Ans=(Ans+calc(i))%Mod;
}
printf("%d\n",Ans);
return 0;
}