昨天也很摆。
最近每天都在因自己的菜自闭。
048 CF1458E Nim Shortcuts
首先转化到二维平面上,每次可以沿着坐标轴逆方向向原点移动。
可以发现每行每列除了至多有一个必败态,否则这两个可以转移,一定有一个必胜。
接下来做法很多:
①
先考察 \(n=1\) 的情况,令 shortcut 为 \((a,b)\)。
显然其只会影响 \(x\geqslant a,y\geqslant b\) 的 \((x,y)\)。
若 \(a<b\):可知 \((b,b)\) 必胜,\((b,b+1)\) 必败,同样可知任意 \((x,x+1)\) 必败(镜像策略),那么 \((x,y)\) 必败等价于删掉第 \(b\) 行之后 \((x,y)\) 必败。
\(a=b\) 没有影响,\(a>b\) 等价于翻转坐标系后的 \(a<b\),\((x,y)\) 必败等价于删掉第 \(a\) 列之后 \((x,y)\) 必败。
一般情况可以考虑增量法,一个个加入 shortcut,那么结论仍然成立。(即 \((x,y)\) 必败当且仅当删掉 \(u\) 行 \(v\) 列后 \((x,y)\) 必败)
树状数组维护二维偏序即可,复杂度 \(O(n\log n)\)。
②
可以发现,所有非 shortcut 的必败态构成一个不超过 \(2n\) 段的分段一次函数,我们只需找到这些转折点。
可以发现加入一个 shortcut 会向上向右延伸出两条必胜态,而其与原本非 shortcut 必败态的折线的交点会变成必胜态,这个点之后的折线会向上/右平移一格。
维护这东西可以用数据结构暴力维护,把所有点的 x,y 坐标抽出来归并排序。(感觉有点麻烦啊)
#include<stdio.h>
#include<algorithm>
#include<map>
#define lowbit(x) (x&-x)
using namespace std;
const int maxn=200005;
int n,q,s,tot;
int t[maxn],ans[maxn],num[maxn];
map<int,int>mp,visx,visy;
map<pair<int,int>,int>rec;
struct point{
int x,y,id;
}p[maxn];
inline int cmp(point a,point b){
return a.x<b.x||(a.x==b.x&&a.y<b.y)||(a.x==b.x&&a.y<b.y&&a.id<b.id);
}
void update(int x,int v){
for(int i=x;i<=tot;i+=lowbit(i))
t[i]+=v;
}
int query(int x){
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=t[i];
return res;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].x,&p[i].y),num[i]=p[i].y,rec[make_pair(p[i].x,p[i].y)]=1;
for(int i=1;i<=q;i++){
scanf("%d%d",&p[n+i].x,&p[n+i].y);
p[n+i].id=i,num[n+i]=p[n+i].y-1;
if(rec.count(make_pair(p[n+i].x,p[n+i].y)))
ans[i]=1;
}
sort(num+1,num+1+n+q),sort(p+1,p+1+n+q,cmp);
for(int i=1;i<=n+q;i++)
if(i==1||num[i]!=num[i-1])
mp[num[i]]=++tot;
for(int i=1;i<=n+q;i++){
int nx=p[i].x-s,ny=p[i].y-query(mp[p[i].y-(p[i].id==0? 0:1)]);
if(p[i].id==0){
if(nx<ny&&visy[p[i].y]==0)
visy[p[i].y]=1,update(mp[p[i].y],1);
if(nx>ny&&visx[p[i].x]==0)
visx[p[i].x]=1,s++;
}
if(p[i].id&&ans[p[i].id]==0&&visx.count(p[i].x)==0&&visy.count(p[i].y)==0)
ans[p[i].id]=(nx==ny);
}
for(int i=1;i<=q;i++)
puts(ans[i]==0? "WIN":"LOSE");
return 0;
}
049 CF1172C2 Nauuo and Pictures (hard version)
很神秘的一道题。
可以发现,对于一张图片,我们只需考虑它的权值、喜欢的图片的总权值,不喜欢的图片的总权值。
立即得到一个 dp:\((f/g)_{i,j,k}\) 表示目前照片是喜欢/不喜欢,喜欢的总权值为 \(i\),不喜欢的总权值为 \(j\),目前权值为 \(k\) 的期望权值。(操作次数是可以表示出来的)
转移:
有一个很神秘的性质,\(f_{i,j,k}=kf_{i,j,1}\)。
证明可以考虑归纳,然后将转移方程展开。也可以考虑将一个权值为 \(k\) 的物品拆成 \(k\) 个权值为 \(1\) 的物品,显然与原问题等价。
重新定义 \(f_{i,j}\) 表示目前喜欢总权值为 \(i\),不喜欢总权值为 \(j\),目前权值为 \(1\) 的期望权值,容易发现前两维都是 \(O(m)\) 的。
复杂度 \(O(n+m^2)\)。(懒可以带一个 \(\log\))
#include<stdio.h>
const int maxn=200005,maxm=3005,mod=998244353;
int n,m,ansf,ansg,sum0,sum1;
int t[maxn],w[maxn],f[maxm][maxm],g[maxm][maxm];
inline int max(int a,int b){
return a>b? a:b;
}
int ksm(int a,int b){
int res=1;
while(b){
if(b&1)
res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&t[i]),t[i]^=1;
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
if(t[i]==0)
sum0=(sum0+w[i])%mod;
else sum1=(sum1+w[i])%mod;
}
for(int s=m;s>=0;s--)
for(int i=max(0,s-sum1);i<=s;i++){
int j=s-i;
if(s<m){
int iv=ksm(sum0+i+sum1-j,mod-2);
f[i][j]=(2ll*iv*f[i+1][j]+1ll*(sum0+i-1)*iv%mod*f[i+1][j]+1ll*(sum1-j)*iv%mod*f[i][j+1])%mod;
g[i][j]=(1ll*(sum0+i)*iv%mod*g[i+1][j]+1ll*(sum1-j-1)*iv%mod*g[i][j+1])%mod;
}
else f[i][j]=g[i][j]=1;
}
ansf=f[0][0],ansg=g[0][0];
for(int i=1;i<=n;i++)
printf("%d\n",1ll*w[i]*(t[i]==0? ansf:ansg)%mod);
return 0;
}
050 AGC057E RowCol/ColRow Sort
不知不觉就到 50 了!
根据排序网络那一套理论,能得到矩阵 B,当且仅当将 \(\leqslant k\) 的数设为 \(1\) 后排序能得到 \(B\) 对应的 01 矩阵。
我们观察每一行,每一列的 \(1\) 个数 \(r_i,c_i\) 在操作后的影响。
Row-sort:\(r\) 不变,\(c\) 排序;Column-sort:\(c\) 不变,\(r\) 排序。
搞不懂。
051 ABC249H Dye Color
题意好难懂啊。。。
考虑停时定理,令 \(f(i)\) 为 \(i\) 个颜色一样的球对应的势能,
列出递推:
就是枚举当前颜色选了多少个,非当前颜色选了多少个,如果选了 \(k\) 个球,每个颜色选择概率都是 \(\frac{k}{N}\)。
对于每个 \(n\),枚举 \(i\),后面的系数拆一拆预处理一下就好了,复杂度 \(O(n^2)\)。
不知道为什么这么菜,推了好久。。。
式子不知道为啥不对,到时候再看吧。。。