HDU校赛 | 2019 Multi-University Training Contest 1

时间:2023-03-10 03:36:41
HDU校赛 | 2019 Multi-University Training Contest 1

2019 Multi-University Training Contest 1

http://acm.hdu.edu.cn/contests/contest_show.php?cid=848

1001. Blank

这题我打比赛的时候想到正解了没敢写...

设\(f_{a,b,c,d}\)表示\(\{0,1,2,3\}​\)最后一次出现的位置排序之后的结果,那么每次枚举四种情况转移就好了。

复杂度\(O(Tn^4)\),由于转移的循环除了个\(4!\)的常数所以跑的很快。

#include<bits/stdc++.h>
using namespace std; void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
} void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define pii pair<int,int >
#define vec vector<int > #define pb push_back
#define mp make_pair
#define fr first
#define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 998244353; int f[2][102][102][102],n,m,ans;
vector<pii > s[102]; void add(int &x,int y) {x+=y;if(x>=mod) x-=mod;} int check(int a,int b,int c,int d) {
for(vector<pii > :: iterator i=s[a].begin();i!=s[a].end();i++)
if((b>=i->fr)+(c>=i->fr)+(d>=i->fr)+1!=i->sc) return 0;
return 1;
} void solve() {
read(n),read(m);
for(int i=1,l,r,x;i<=m;i++) read(l),read(r),read(x),s[r].pb(mp(l,x));
f[0][0][0][0]=1;
for(int a=0,t=0;a<=n;a++,t^=1) {
for(int b=0;b<=a+1;b++)
for(int c=0;c<=b;c++)
for(int d=0;d<=c;d++)
f[t^1][b][c][d]=0;
for(int b=0;b<(a?a:1);b++)
for(int c=0;c<(b?b:1);c++)
for(int d=0;d<(c?c:1);d++) {
if(!check(a,b,c,d)) continue;
add(f[t^1][b][c][d],f[t][b][c][d]);
add(f[t^1][a][c][d],f[t][b][c][d]);
add(f[t^1][a][b][d],f[t][b][c][d]);
add(f[t^1][a][b][c],f[t][b][c][d]);
if(a==n) add(ans,f[t][b][c][d]);
}
}
write(ans);
} void clear() {
ans=0;
memset(f,0,sizeof f);
for(int i=1;i<=n;i++) s[i].clear();
} int main() {
int t;read(t);while(t--) solve(),clear();
return 0;
}

1002. Operation

赛后改的。。

考虑记录前缀线性基,然后我们模仿单调队列,贪心的让每一位的位置尽可能的靠后。

实现的话考虑对线性基每一位记录这一位最前出现的位置,这是因为这一位可能是很多数异或起来的,取最前面那个,实现可以参照代码。

复杂度\(O(Tn\log n)\)。

#include<bits/stdc++.h>
using namespace std; void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
} void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define pii pair<int,int >
#define vec vector<int > #define pb push_back
#define mp make_pair
#define fr first
#define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7; int v[maxn],n,a[maxn][31],p[maxn][31],m; void append(int x,int pos) {
for(int i=30;~i;i--) a[pos][i]=a[pos-1][i],p[pos][i]=p[pos-1][i];
int pps=pos;
for(int i=30;~i;i--)
if(x&(1<<i)) {
if(!a[pps][i]) {a[pps][i]=x;p[pps][i]=pos;return ;}
if(pos>p[pps][i]) swap(x,a[pps][i]),swap(pos,p[pps][i]);
x^=a[pps][i];
}
} int query(int l,int r) {
int ans=0;
for(int i=30;~i;i--)
if(p[r][i]>=l&&(ans^a[r][i])>ans) ans^=a[r][i];
return ans;
} void solve() {
read(n),read(m);
for(int i=1,x;i<=n;i++) read(x),append(x,i);
int la=0;
for(int i=1;i<=m;i++) {
int op,l,r;read(op);
if(op==0) {
read(l),read(r);l=(l^la)%n+1,r=(r^la)%n+1;if(l>r) swap(l,r);
write(la=query(l,r));
} else {
read(r);r=r^la;append(r,++n);
}
}
} void clear() {
for(int i=1;i<=n;i++) {
memset(a[i],0,sizeof a[i]);
memset(p[i],0,sizeof p[i]);
}
} int main() {
int t;read(t);while(t--) solve(),clear();
return 0;
}

1004. Vacation

二分答案,然后从后往前枚举判断就好了。

复杂度\(O(Tn\log v)\)。

#include<bits/stdc++.h>
using namespace std; void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
} void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define pii pair<int,int >
#define vec vector<int > #define pb push_back
#define mp make_pair
#define fr first
#define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = 1e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7; int n,l[maxn],s[maxn],v[maxn]; int check(lf t) {
lf lim=-1e9;
for(int i=n;~i;i--) {
lf tmp=(lf)s[i]-(lf)v[i]*t;
if(tmp>lim) lim=tmp;
lim+=l[i];
}//printf("lim :: %.6lf\n",lim);
return lim-l[0]<=0;
} void solve() {
for(int i=0;i<=n;i++) read(l[i]);
for(int i=0;i<=n;i++) read(s[i]);
for(int i=0;i<=n;i++) read(v[i]);
lf l=0,r=1e9;
while(fabs(r-l)>1e-8) {
lf mid=(l+r)*0.5;
if(check(mid)) r=mid;
else l=mid;
}printf("%.8lf\n",l);
} int main() {
while(scanf("%d",&n)!=EOF) solve();
return 0;
}

1005. Path

建出最短路径图,求最小割。

代码挖坑。

1012. Sequence

首先我们把\(a\)写成生成函数\(\sum_{i=1}^{n}a_ix^i\)。

对于一次\(k\)操作,显然\(a\)的生成函数会乘上\(\sum_{i\geqslant 0}x^{ik}\)。

显然顺序不影响答案。

那么统计一下每个操作出现了多少次,答案就是:

\[\left(\sum_{i=1}^{n}a_ix^i\right)\cdot\prod_{k=1}^3\left(\sum_{i\geqslant 0}x^{ik}\right)^{cnt_k}
\]

注意到:

\[\left(\sum_{i\geqslant 0}x^{ik}\right)^{t}=\sum_{i\geqslant 0}\binom{i+t-1}{t-1}x^{ik}
\]

所以做三遍\(\rm NTT\)就可以了,复杂度\(O(Tn\log n)\)。

#include<bits/stdc++.h>
using namespace std; void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
} void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define pii pair<int,int >
#define vec vector<int > #define pb push_back
#define mp make_pair
#define fr first
#define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
#define ll long long const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 998244353; int n,m,a[maxn],t[4],b[maxn],N,bit,pos[maxn],w[maxn],mxn,fac[maxn],ifac[maxn]; int qpow(int a,int x) {
int res=1;
for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
return res;
} int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y) {return x-y<0?x-y+mod:x-y;} void prepare() {
for(mxn=1,bit=0;mxn<=n*2;mxn<<=1,bit++);N=mxn;
w[0]=1,w[1]=qpow(3,(mod-1)/mxn),fac[0]=ifac[0]=1;
for(int i=2;i<=N;i++) w[i]=1ll*w[i-1]*w[1]%mod;
for(int i=1;i<N;i++) pos[i]=pos[i>>1]>>1|((i&1)<<(bit-1));
for(int i=1;i<m;i++) fac[i]=1ll*fac[i-1]*i%mod;
for(int i=1;i<m;i++) ifac[i]=1ll*ifac[i-1]*qpow(i,mod-2)%mod;
} void ntt(int *r,int op) {
for(int i=1;i<N;i++) if(pos[i]>i) swap(r[i],r[pos[i]]);
for(int i=1,d=mxn>>1;i<N;i<<=1,d>>=1)
for(int j=0;j<N;j+=i<<1)
for(int k=0;k<i;k++) {
int x=r[j+k],y=1ll*r[i+j+k]*w[k*d]%mod;
r[j+k]=add(x,y),r[i+j+k]=del(x,y);
}
if(op==-1) {
reverse(r+1,r+N);int d=qpow(N,mod-2);
for(int i=0;i<N;i++) r[i]=1ll*r[i]*d%mod;
}
} int c(int a,int b) {return 1ll*fac[a]*ifac[b]%mod*ifac[a-b]%mod;} void calc(int k) {
for(int i=0;i<N;i++) b[i]=0;
b[0]=1;
for(int i=1;i*k<=n;i++) b[i*k]=c(i+t[k]-1,t[k]-1);
ntt(a,1),ntt(b,1);
for(int i=0;i<N;i++) a[i]=1ll*a[i]*b[i]%mod;
ntt(a,-1);
for(int i=n+1;i<N;i++) a[i]=0;
} void solve() {
read(n),read(m);prepare();
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1,x;i<=m;i++) read(x),t[x]++;
for(int i=1;i<=3;i++) calc(i);ll ans=0;
for(int i=1;i<=n;i++) ans^=1ll*i*a[i];
printf("%lld\n",ans);
} void clear() {
t[1]=t[2]=t[3]=0;
for(int i=0;i<N;i++) a[i]=b[i]=0;
} int main() {
int t;read(t);while(t--) solve(),clear();
return 0;
}