AGC 043 C,D 题解
Posted Gary2005
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AGC 043 C,D 题解相关的知识,希望对你有一定的参考价值。
AGC 043 C,D 题解
C - Giant Graph
首先可以理解成一个\\(N\\times N\\times N\\)的立方体从\\((N,N,N)\\)开始按照\\(x+y+z\\)降序贪心添加。
一个点不被选当且仅当按照\\(x,y,z\\)某一个方向可以到达一个选择的。
直接用\\(SG\\)函数即可。
由于\\(SG\\)的值域是\\(O(\\sqrt N)\\)的,所以可以暴力卷积,也可以用\\(O(\\sqrt N\\log\\sqrt N)\\)的FWT。
时间复杂度\\(O(N)\\)。
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<\'0\'||ch>\'9\'){
// ch=getchar();
// }
// while(ch>=\'0\'&&ch<=\'9\'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=1e5+233;
int n;
int sg1[MAXN<<1],sg2[MAXN<<1],sg3[MAXN<<1];
int a1[MAXN<<1],a2[MAXN<<1],a3[MAXN<<1];
const int MOD=998244353;
int tmp[1<<17];
const int iv2=(MOD+1)/2;
void FMT(int * a,int x){
for(int k=1;k<n;k<<=1){
for(int j=0;j<n;j+=(k<<1)){
rep(i,k){
if(x==1) (tmp[i+j]=(a[i+j]+a[i+j+k])%MOD,tmp[i+j+k]=(MOD+a[i+j]-a[i+j+k])%MOD);
else (tmp[i+j]=1ll*(a[i+j]+a[i+j+k])*iv2%MOD,tmp[i+j+k]=1ll*(MOD+a[i+j]-a[i+j+k])*iv2%MOD);
}
}
rep(i,n) a[i]=tmp[i];
}
}
vector<int> g[MAXN];
namespace GRAPH{
void read(){
int m;
scanf("%d",&m);
rb(i,1,m){
int u,v;
scanf("%d%d",&u,&v);
if(v<u) swap(u,v);
g[u].PB(v);
}
}
int Mex(vector<int> v){
sort(ALL(v));
v.erase(unique(ALL(v)),v.end());
v.PB(1000000000);
rep(i,v.size()) if(v[i]!=i) return i;
return 0;
}
vector<int> gao(){
vector<int> sg(n+1,0);
rl(i,n,1){
vector<int> v;
for(auto it:g[i]) v.PB(sg[it]);
sg[i]=Mex(v);
}
return sg;
}
void clear(){
rb(i,1,n) g[i].clear();
}
}
int main(){
scanf("%d",&n);
GRAPH::read();
vector<int> tmp=GRAPH::gao();
rb(i,1,n) sg1[i]=tmp[i];
GRAPH::clear();
GRAPH::read();
tmp=GRAPH::gao();
rb(i,1,n) sg2[i]=tmp[i];
GRAPH::clear();
GRAPH::read();
tmp=GRAPH::gao();
rb(i,1,n) sg3[i]=tmp[i];
GRAPH::clear();
int ttmp=1;
while(ttmp<n) ttmp<<=1;
int _1018=1;
rb(i,1,18) _1018=10ll*_1018%MOD;
int T=1;
rb(i,1,n) T=1ll*T*_1018%MOD,(a1[sg1[i]]+=T)%=MOD;
T=1;
rb(i,1,n) T=1ll*T*_1018%MOD,(a2[sg2[i]]+=T)%=MOD;
T=1;
rb(i,1,n) T=1ll*T*_1018%MOD,(a3[sg3[i]]+=T)%=MOD;
n=ttmp;
FMT(a1,1);
FMT(a2,1);
FMT(a3,1);
rep(i,n) a1[i]=1ll*a1[i]*a2[i]%MOD*a3[i]%MOD;
FMT(a1,-1);
printf("%d\\n",a1[0]);
return 0;
}
D - Merge Triplets
如果一个元素不是前缀最大值则一定和前一个元素属于同一堆。
这样就有长度为\\(1,2,3\\) 的段。
然后将\\(1,2\\)两两匹配。
剩下只需要有\\(3\\)的倍数个\\(1\\)即可。
记\\(dp[i][j][k]\\)表示考虑了前\\(i\\)个,有\\(j\\)个1段,\\(k\\) 个2 段的方案数。
可以发现\\(j,k\\)之中必有一个\\(0\\)。
所以状态时\\(O(N^2)\\)的,转移直接枚举下一段长度即可。
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<\'0\'||ch>\'9\'){
// ch=getchar();
// }
// while(ch>=\'0\'&&ch<=\'9\'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=6002;
int MOD,n,dp[MAXN][MAXN<<1];
int T(int i,int k){
if(k==1) return 1;
if(k==2) return i+1;
return 1ll*(i+1)*(i+2)%MOD;
}
int main(){
scanf("%d%d",&n,&MOD);
n*=3;
dp[0][MAXN]=1;
rb(i,0,n-1){
rb(j,-n,n)
if(dp[i][j+MAXN])
rb(k,1,min(3,n-i)){
if(k==3){
(dp[i+3][j+MAXN]+=1ll*dp[i][j+MAXN]*T(i,k)%MOD)%=MOD;
}
if(k==2){
(dp[i+2][j-1+MAXN]+=1ll*dp[i][j+MAXN]*T(i,k)%MOD)%=MOD;
}
if(k==1){
(dp[i+1][j+1+MAXN]+=1ll*dp[i][j+MAXN]*T(i,k)%MOD)%=MOD;
}
}
}
int rest=0;
rb(i,0,n) if(i%3==0) (rest+=dp[n][i+MAXN])%=MOD;
printf("%d\\n",rest);
return 0;
}
以上是关于AGC 043 C,D 题解的主要内容,如果未能解决你的问题,请参考以下文章
AGC 043 C - Giant Graph SG函数 dp 贪心