省选武汉联测 10/ GDKOI 2023 提高组 D1
今天感觉打的挺智力的。为啥全员 160。
感觉得了一种病,一种不挂火车头就会死的病。
看到题发现是 GDKOI 2023 提高组 D1。于是根据这两场上的时间非常近推断下一场是 D2。然后得到确凿消息明天确实要考 D2。看了看 D2 的题,T1 是个可做题,T2 是个神秘计数,T3 感觉还好。
矩阵
标算是随机一个向量
把
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int mod=998244353;
int n,A[3010][3010],B[3010][3010],C[3010][3010],sum1[3010],sum2[3010];
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
bool solve(int x=131){
static int a[3010][3010],b[3010][3010],c[3010][3010];
for(int i=1;i<=n;i++){
int pw=1;sum1[i]=sum2[i]=0;
for(int j=1;j<=n;j++){
pw=1ll*pw*x%mod;
a[i][j]=A[i][j];
b[i][j]=1ll*B[i][j]*pw%mod;
c[i][j]=1ll*C[i][j]*pw%mod;
sum1[i]=add(sum1[i],b[i][j]);
sum2[i]=add(sum2[i],c[i][j]);
}
}
for(int i=1;i<=n;i++){
int ans=0;
for(int j=1;j<=n;j++)ans=(ans+1ll*a[i][j]*sum1[j])%mod;
if(ans!=sum2[i])return false;
}
for(int j=1;j<=n;j++){
int pw=1;sum1[j]=sum2[j]=0;
for(int i=1;i<=n;i++){
pw=1ll*pw*x%mod;
a[i][j]=1ll*A[i][j]*pw%mod;
b[i][j]=B[i][j];
c[i][j]=1ll*C[i][j]*pw%mod;
sum1[j]=add(sum1[j],a[i][j]);
sum2[j]=add(sum2[j],c[i][j]);
}
}
for(int j=1;j<=n;j++){
int ans=0;
for(int i=1;i<=n;i++)ans=(ans+1ll*b[i][j]*sum1[i])%mod;
if(ans!=sum2[j])return false;
}
return true;
}
int read(){
int x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
return x;
}
int main(){
int tim=read();
while(tim--){
n=read();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)A[i][j]=read();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)B[i][j]=read();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)C[i][j]=read();
bool jud=true;
if(!solve())jud=false;
puts(jud?"Yes":"No");
}
return 0;
}
错排
推法是前面
设后边这个是
实际上可以根据这个递推式整莫队。过程有点神秘。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int mod=998244353,sq=450,mx=200000;
int n,m,Q,cnt,jc[200010],inv[200010],ans[200010];
int C(int n,int m){
if(n<m)return 0;
return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
}
struct Ques{
int n,m,id;
bool operator<(const Ques&s)const{
return n/sq==s.n/sq?m>s.m:n<s.n;
}
}q[200010];
int main(){
jc[0]=inv[0]=inv[1]=1;
for(int i=2;i<=mx;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=mx;i++)jc[i]=1ll*jc[i-1]*i%mod;
scanf("%d",&Q);
for(int i=1;i<=Q;i++){
scanf("%d%d",&n,&m);
if(n>=2*m){
q[++cnt]={n-2*m,m+1,i};
ans[i]=1ll*jc[n-m]*jc[m]%mod;
}
}
sort(q+1,q+cnt+1);
int x,y=0,f0,f1,f2;
for(int i=1;i<=Q;i++){
if(y<q[i].m)x=0,y=mx,f0=f1=0,f2=1;
while(x<q[i].n){
x++;
f0=f1;f1=f2;
f2=1ll*(1ll*(x-1+y-1+mod)%mod*f1%mod+f0)%mod*inv[x]%mod;
}
while(x>q[i].n){
x--;
f2=f1;f1=f0;
f0=1ll*(1ll*x*f2%mod-1ll*(x-1+y-1+mod)%mod*f1%mod+mod)%mod;
}
while(y>q[i].m){
y--;
f2=(f2-f1+mod)%mod;
f1=(f1-f0+mod)%mod;
f0=(1ll*x*f2%mod-1ll*(x-1+y-1+mod)%mod*f1%mod+mod)%mod;
}
ans[q[i].id]=1ll*ans[q[i].id]*f2%mod;
}
for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);
return 0;
}
异或图
好神秘。明天还有两个比这个更神秘的题。不过明天 T1 应该还是能写的。
首先考虑
加上边,考虑一个暴力容斥。枚举边集,钦定它们不满足,即连通块内所有点相等。连通块大小偶数的时候没贡献,只需要对奇数的做一次上边的 dp。
爆跑是不行的,考虑枚举最后形成的连通块的集合。一个连通块的容斥系数是选边集
设
//躯樹の墓守 隣の庭は青い(庭師 + Aoi)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <unordered_map>
#define int long long
using namespace std;
const int mod=998244353;
int n,m,k,ans,a[20],w[1<<15],p[20],pos[20],to[20];
int g[20][1<<15],f[1<<15];
unordered_map<int,int>dp[1<<15];
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int lowbit(int x){return x&-x;}
bool cmp(int x,int y){return a[x]<a[y];}
signed main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=0;i<n;i++)scanf("%lld",&a[i]),a[i]++,p[i]=i;
sort(p,p+n,cmp);
for(int i=0;i<n;i++)pos[p[i]]=i;
sort(a,a+n);
for(int i=0;i<n;i++)w[1<<i]=a[i]%mod;
for(int i=1;i<=m;i++){
int u,v;scanf("%lld%lld",&u,&v);
u=pos[u-1],v=pos[v-1];
to[u]|=1<<v,to[v]|=1<<u;
}
for(int t=0;t<n;t++){
g[t][1<<t]=1;
for(int i=0;i<(1<<t);i++){
int ret=i|(1<<t);
f[ret]=(f[ret]+g[t][ret])%mod;
int tmp=i^((1<<t)-1);
for(int s=tmp;s;s=(s-1)&tmp){
if((to[t]&s)&&lowbit(s)<lowbit(ret)){
g[t][ret|s]=(g[t][ret|s]-1ll*g[t][ret]*f[s]%mod+mod)%mod;
}
}
}
}
dp[0][0]=1;
for(int i=0;i<(1<<n);i++){
int ret=((1<<n)-1)^i,pos=lowbit(ret);ret^=pos;
for(pair<int,int>x:dp[i]){
int j=x.first;
if(!x.second)continue;
for(int t=ret;;t=(t-1)&ret){
int s=t|pos;
if(__builtin_popcountll(s)&1)dp[i|s][j|pos]=(dp[i|s][j|pos]+1ll*dp[i][j]*f[s])%mod;
else dp[i|s][j]=(dp[i|s][j]+1ll*dp[i][j]*f[s]%mod*w[pos])%mod;
if(!t)break;
}
}
}
if(!k)ans=dp[(1<<n)-1][0];
for(int i=1;i<(1<<n);i++){
int tot=0;
for(int t=60;t>=0;t--){
int s=0;
for(int j=0;j<n;j++)if((i>>j)&1)s^=a[j]>>t+1;
if(s!=(k>>t+1))break;
int f=1,g=0,h=1,c=0,U=(1ll<<t)-1;
for(int j=0;j<n;j++){
if(!((i>>j)&1))continue;
if(!((a[j]>>t)&1)){
f=1ll*(a[j]&U)%mod*f%mod;
g=1ll*(a[j]&U)%mod*g%mod;
}
else{
c^=1;
int sf=f,sg=g;
f=(1ll*(a[j]&U)%mod*sg%mod+1ll*(U+1)%mod*sf%mod)%mod;
g=(1ll*(a[j]&U)%mod*sf%mod+1ll*(U+1)%mod*sg%mod)%mod;
}
h=1ll*(a[j]&U)%mod*h%mod;
}
if(!c)f=(f-h+mod)%mod;
else g=(g-h+mod)%mod;
if(!((k>>t)&1))tot=(tot+1ll*f*qpow((U+1)%mod,mod-2))%mod;
else tot=(tot+1ll*g*qpow((U+1)%mod,mod-2))%mod;
}
ans=(ans+1ll*dp[(1<<n)-1][i]*tot)%mod;
}
printf("%lld\n",ans);
return 0;
}
快踩
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】