UR #19 简要题解
比赛总结
开场把 \(\text{T1}\) 读成一道不可做,然后又成功写完 \(\text{T2}\) 带 \(log\) 的做法后以为过不了,并且成功的傻逼的以为正确的 \(n^3\) 做法思路没法做,以至 \(2.5h\) 后才写完两道的 \(170\)。最后十分钟才发现自己读错题,只好打出 \(\text{GG}\) 。
省选这样的话就可以退役了。
T1
\(m+1\) 的限制不用管。可以发现如果只有环的操作充要条件是只考虑 \(1\) 的边度数全部相等。于是变量就只有 \(n\) 个。二分图可以拆成每个点分别操作。
高斯消元即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
bitset<N> b[N];
int n,m,deg[N],val[N];
void guass(){
for(int i=1;i<=n;i++){
if(!b[i][i]){
int p=0;
for(int j=i+1;j<=n;j++)if(b[j][i]){p=j;break;}
if(!p)continue;
swap(b[i],b[p]);
}
for(int j=1;j<=n;j++)if(i^j){
if(b[j][i])b[j]^=b[i];
}
}
for(int i=1;i<=n;i++)if(!b[i][i]&&b[i][n+1]){
puts("no");
return ;
}
puts("yes");
}
void Main(){
cin >> n >> m;
for(int i=1;i<=n;i++)b[i].reset();
for(int i=1;i<=n;i++)deg[i]=0,val[i]=0;
for(int i=1;i<=m;i++){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
b[u][v] = b[v][u] = 1;
deg[u]^=1,deg[v]^=1;
if(w)val[u]^=1,val[v]^=1;
}
for(int i=1;i<=n;i++)b[i][i]=deg[i],b[i][n+1]=val[i];
guass();
}
int main()
{
int T;cin >> T;
while(T--){
Main();
}
}
T2
简要题解:猎人杀,没了
拆成每个点的贡献,之后就是这个位置需要 \(a\) 个,其它位置需要 \(b\) 个,概率就是这个位置不是最后填满的概率。
容斥之后发现只需要算 \(f_{i,j}\) 表示 \(i\) 个人分 \(j\) 个东西,人和东西有标号,每个人不能分到 \(\ge b\) 个。
\(NTT\) 去做背包即可 \(O(n^3\log n)\)。
当然这个有一个 \(O(n^3)\) 的 \(\text{dp}\),我们考虑最后一个物品放给谁,然后现在不合法的情况只有一种:某个人分到了恰好 \(b\) 个。
然后转移就是 \(O(1)\) 的了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
int sub(int a,int b){a-=b;return a<0?a+mod:a;}
int mul(int a,int b){return (ll)a*b%mod;}
int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/* math */
int n,a,b;
typedef vector<int> Poly;
namespace Ploy_template {
int rev[4000010];
Poly Add(Poly a,Poly b){
a.resize(max(a.size(),b.size()));
for(size_t i=0;i<b.size();i++)a[i] = add(a[i],b[i]);
return a;
}
Poly Sub(Poly a,Poly b){
a.resize(max(a.size(),b.size()));
for(size_t i=0;i<b.size();i++)a[i] = sub(a[i],b[i]);
return a;
}
Poly rever(Poly x){
reverse(x.begin(),x.end());
return x;
}
inline void DFT(int *t,int n,int tpe){
int l=0;while(1<<l<n)++l;
for(int i=1;i<n;i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<n;i++) if(rev[i]>i) swap(t[rev[i]],t[i]);
for(int step=1;step<n;step<<=1){
int wn = qpow(3, (mod-1)/(step<<1));
for(int i=0;i<n;i+=step<<1){
int w = 1;
for(int j=0;j<step;j++,w = mul(w,wn)){
int x = t[i+j], y = mul(w,t[i+j+step]);
t[i+j] = add(x,y); t[i+j+step] = sub(x,y);
}
}
}
if(tpe==1)return ;
for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
int inv = qpow(n,mod-2);
for(int i=0;i<n;i++)t[i] = mul(t[i], inv);
}
inline Poly NTT(Poly a, int n, Poly b, int m){
int len = n+m-1,l=0;while(1<<l<len)++l;
static Poly res;
res.resize(1<<l); a.resize(1<<l),b.resize(1<<l);
DFT(&a[0],1<<l,1),DFT(&b[0],1<<l,1);
for(int i=0;i<(1<<l);i++)res[i] = mul(a[i],b[i]);
DFT(&res[0],1<<l,-1);
res.resize(len);
return res;
}
Poly NTT(Poly a, Poly b){
return NTT(a,a.size(),b,b.size());
}
}
using namespace Ploy_template;
const int N = 260;
int ifac[N*N],fac[N*N];
inline void init(int n=250*260){
ifac[0]=fac[0]=1;for(int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
ifac[n]=qpow(fac[n],mod-2);for(int i=n-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
}
Poly f;
Poly g[N];
inline int binom(int a,int b){
if(a<b)return 0;
return mul(fac[a],mul(ifac[b],ifac[a-b]));
}
void output(Poly& t){
for(size_t i=0;i<t.size();i++)cout << t[i] << " ";puts("");
}
Poly multar(Poly a,Poly b){
Poly c(a.size(),0);
for(size_t i=0;i<a.size();i++)c[i]=mul(a[i],b[i]);
return c;
}
int main()
{
init();
cin >> n >> a >> b;
f.resize(b);
for(int i=0;i<b;i++)f[i] = ifac[i];
int Lenth = (n-1)*(b-1)+1;
int len = 1;
while(Lenth>len)len<<=1;
f.resize(len);
DFT(&f[0],len,1);
g[0].resize(len);
for(int i=0;i<len;i++)g[0][i]=1;
for(int i=1;i<=n-1;i++)g[i]=multar(g[i-1],f);
int ret=0;//for debug
for(int i=0;i<n;i++){
DFT(&g[i][0],len,-1);
int d = qpow(i+1,mod-2);
int P = qpow(d,a);
P=mul(P,binom(n-1,i));
if(i&1){P=sub(0,P);}
for(int j=0;j<len;j++){
int q = mul(g[i][j],fac[j]);
q = mul(q, binom(a-1+j,a-1));
q=mul(P,q);
ret=add(ret,q);
P=mul(P,d);
}
}
cout << mul(sub(1,ret),n) << endl;
}
T3
从后向前,维护下标为时间的后缀 \(min\) 以及修改次数。
这玩意是 Segment Tree Beats。
代码(被卡常)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+6;
namespace FastIO {
#define SIZE 100000
inline char nc(){
// return getchar();
static char buf[SIZE],*p1=buf+SIZE,*p2=buf+SIZE;
if(p1==p2) p2=(p1=buf)+fread(buf,1,SIZE,stdin);
return p1==p2?-1:*p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
template <class T> inline void read(T &x){
register double tmp = 1;
register bool sign = 0;
x = 0;
register char ch=nc();
for(;ch<'0'||ch>'9';ch=nc()) if(ch=='-') sign=1;
for(;ch>='0'&&ch<='9';ch=nc()) x=x*10+ch-'0';
if(ch=='.') for(ch=nc();ch>='0'&&ch<='9';ch=nc()) tmp/=10.0,x+=tmp*(ch-48);
if(sign) x=-x;
}
inline void read(char *s){
register char ch=nc();
for (;blank(ch);ch=nc());
for (;!blank(ch);ch=nc()) *s++=ch;
*s=0;
}
inline void read(char &c){
for(c=nc();blank(c);c=nc());
}
template <class T> inline void print(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar('0'+x%10);
}
template <class T> inline void print(T x,char c){
print(x),putchar(c);
}
}
using namespace FastIO;
int n,m;
struct dat{
int mx,secmx,Add;
}t[N<<2];
#define mid ((l+r)>>1)
inline void pushup(int x){
if(t[x<<1].mx>t[x<<1|1].mx){
t[x].mx=t[x<<1].mx;
t[x].secmx=max(t[x<<1].secmx,t[x<<1|1].mx);
}else{
t[x].mx=t[x<<1|1].mx;
if(t[x<<1].mx==t[x<<1|1].mx){
t[x].secmx=max(t[x<<1|1].secmx,t[x<<1].secmx);
}else t[x].secmx=max(t[x<<1|1].secmx,t[x<<1].mx);
}
}
inline void adval(int x,int val,int Ad){
if(t[x].mx>val){
t[x].mx=val;
t[x].Add+=Ad;
}
}
inline void pushdown(int x){
if(t[x].Add){
adval(x<<1,t[x].mx,t[x].Add);
adval(x<<1|1,t[x].mx,t[x].Add);
t[x].Add=0;
}
}
inline void build(int x,int l,int r){
t[x].mx=1<<30, t[x].secmx=-(1<<30);
if(l==r)return ;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
inline void Ad(int x,int x1){
if(t[x].secmx<x1){
adval(x,x1,1);return ;
}pushdown(x);
Ad(x<<1,x1);
Ad(x<<1|1,x1);
pushup(x);
}
inline void modify(int x,int l,int r,int ql,int qr,int v){
// if(x==1)cout << ql << " " << qr << " " << v << endl;
if(ql<=l&&qr>=r){Ad(x,v);return;}
pushdown(x);
if(ql<=mid)modify(x<<1,l,mid,ql,qr,v);
if(qr>mid) modify(x<<1|1,mid+1,r,ql,qr,v);
pushup(x);
}
inline int query(int x,int l,int r,int p){
if(l==r)return t[x].Add;
pushdown(x);
if(p<=mid)return query(x<<1,l,mid,p);
else return query(x<<1|1,mid+1,r,p);
}
typedef pair<int,int> pi;
pair<int, pair<pi,int> > opt[N<<1];
int c1;
int a[N];int lst[N];
pair<int,pi> q[N];
int c2;
int ans[N];
int M=1;
int main()
{
read(n),read(m);
build(1,1,m);
for(int i=1;i<=n;i++){
read(a[i]);
lst[i]=1;
}
for(int i=1,op,x,v;i<=m;i++){
read(op);
ans[i] = -1;
if(op==1){
read(x),read(v);
opt[++c1]=make_pair(x,make_pair(pi(lst[x],M),a[x]));
a[x] = v;
lst[x]=++M;
}else{
read(x);
q[++c2]=make_pair(x,make_pair(M,i));
}
}
for(int i=1;i<=n;i++){
opt[++c1]=make_pair(i,make_pair(pi(lst[i],M),a[i]));
}
sort(opt+1,opt+c1+1),sort(q+1,q+c2+1);
build(1,1,M);
for(int i=n,l,r,v;i;i--){
while(c1&&opt[c1].first==i){
l=opt[c1].second.first.first,r=opt[c1].second.first.second,v=opt[c1].second.second;
if(l<=r)modify(1,1,M,l,r,v);
--c1;
}
while(c2&&q[c2].first==i){
ans[q[c2].second.second]=query(1,1,M,q[c2].second.first);
--c2;
}
}
for(int i=1;i<=m;i++){
if(ans[i]!=-1){
print(ans[i],'\n');
}
}
}