【学习笔记】AGC061

开个坑然后慢慢填

我为什么要做题,不如颓废

A - Long Shuffle

这题好难啊 是我太菜了吗

n n n是偶数时,我们发现只会在 A 2 i − 1 A_{2i-1} A2i1 A 2 i A_{2i} A2i之间交换,对于 n n n更大的情况似乎没有什么明显的规律 嗯,这就是我自己做这道题时的水平了

其实这道题非常有意思啊,究其本质,还是对数学归纳法的运用。

让我们尝试归纳一下。设 n n n为偶数,那么操作 ( 1 , n ) (1,n) (1,n)相当于 ( 1 , n − 2 ) + ( 3 , n ) (1,n-2)+(3,n) (1,n2)+(3,n)(这里的加法表示操作拼接的意思),接下来的尝试非常脑洞:如果 A 2 i − 1 A_{2i-1} A2i1 A 2 i A_{2i} A2i交换那么这一位是 1 1 1,我们可以把 n n n次操作后的结果看成一个二进制数 x x x,那么两个操作的拼接就等价于每一个位置上的异或,显然我们有结论: x ′ = x ⊕ ( x < < 1 ) x'=x\oplus (x<<1) x=x(x<<1)。这里有意思的地方就在于位运算操作具有分配律,我们把左移操作放进每个异或里面去,然后观察展开后 ( x < < i ) (x<<i) (x<<i)前面的系数,发现 其恰好符合杨辉三角的规律 ,于是可以归纳得出结论: A 2 i − 1 A_{2i-1} A2i1 A 2 i A_{2i} A2i交换当且仅当 ( n / 2 − 1 i − 1 ) \binom{n/2-1}{i-1} (i1n/21)为奇数。

对于 n n n为奇数的情况,显然我们可以看成 ( 1 , n − 1 ) + ( 2 , n ) (1,n-1)+(2,n) (1,n1)+(2,n),只需细致的讨论即可。

如果大佬有高妙的数学方法也欢迎指教

#include<bits/stdc++.h> #define ll long long using namespace std; int T; ll n,K; int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>T; while(T--){ cin>>n>>K,K--; if(n%2==0){ if(((n/2-1)&(K/2))==K/2)K^=1; cout<<K+1<<"\n"; } else{ if(K){ K--; if(((n/2-1)&(K/2))==K/2)K^=1; K++; } if(((n/2-1)&(K/2))==K/2)K^=1; cout<<K+1<<"\n"; } } }

B - Summation By Construction

神仙构造题。是我想不出来的那种

题解告诉我们,可以从邻接矩阵的角度考虑。手玩 n = 3 , 5 n=3,5 n=3,5的情况,可以发现每个颜色必须在每一行恰好出现两次或在每一列恰好出现两次,经过不懈的尝试 题解的提示 ,我们可以得到 n = 5 n=5 n=5时的方案:

5 5 3 3 1 1 4 5 5 3 3 4 4 4 5 5 3 3 2 4 4 5 5 2 2 2 4 4 5 5

不难验证这个构造是正确的。其实对于每种颜色在邻接矩阵上验证即可

然后考虑 n n n为偶数的情况。因为这些情况的构造都是等价的,因此只用考虑 n = 6 n=6 n=6的情形。

接下来的想法非常脑洞。我们考虑在 5 × 5 5\times 5 5×5的基础上扩展, 为什么不是删除一行一列呢,因为我试过了,而且一下午都没做出来 也就是这样:

6 6 4 4 2 . . 5 6 6 4 4 . . 5 5 6 6 4 . . 3 5 5 6 6 . . 3 3 5 5 6 . . . . . . . . .

这个扩展的部分还是比较复杂的 好变态啊 ,注意每种颜色扩展的长度为 3 3 3,以左下角的颜色为例,应该是向下扩展 1 1 1格,再向右扩展 2 2 2格。总之最后结果如下:

6 6 4 4 2 5 2 5 6 6 4 4 5 2 5 5 6 6 4 4 3 3 5 5 6 6 4 3 3 3 5 5 6 6 1 6 3 4 5 2 6 1

注意此时颜色 n n n形成了一个环,这可以通过只改变 1 , 2 , n 1,2,n 1,2,n的路径来解决:

6 6 4 4 2 5 2 5 6 6 4 4 5 1 5 5 6 6 4 4 3 3 5 5 6 6 4 3 3 3 5 5 6 6 1 2 3 4 5 2 6 6

一下午的光阴啊

#include<bits/stdc++.h> #define ll long long using namespace std; int T,n,a[105][105],in[205]; void work(int n){ for(int i=0;i<n;i++){ a[i][i]=a[i][i+1]=n; } for(int i=1;i<=n/2;i++){ int s=n-2*i+1; for(int j=0;j<s;j++){ a[2*i-1+j][(n+j)%(n+1)]=a[2*i-1+j][j]=s; } } for(int i=1;i<=n/2;i++){ int s=n-2*i; for(int j=0;j<s;j++){ a[j][2*i+j]=a[j][2*i+j+1]=s; } } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>T; while(T--){ cin>>n; if(n==2){ cout<<"No"<<"\n"; continue; }cout<<"Yes"<<"\n"; if(n&1){ for(int i=0;i<n;i++){ a[i][i]=a[i][i+1]=n; } for(int i=1;i<=n/2;i++){ int s=n-2*i+1; for(int j=0;j<s;j++){ a[2*i-1+j][(n+j)%(n+1)]=a[2*i-1+j][j]=s; } } for(int i=1;i<=n/2;i++){ int s=n-2*i; for(int j=0;j<s;j++){ a[j][2*i+j]=a[j][2*i+j+1]=s; } } for(int i=0;i<n;i++){ for(int j=0;j<n+1;j++){ cout<<a[i][j]<<' '; }cout<<"\n"; } } else{ work(n-1); for(int i=0;i<n;i++){ for(int j=0;j<n+1;j++){ if(i<n-1&&j<n-1)a[i][j]++; else a[i][j]=0; } } for(int i=1;i<n/2;i++){ int s=n-2*i+1; a[n-1][s-2]=a[2*i-1][n]=a[2*i-2][n]=s; } for(int i=1;i<n/2;i++){ int s=n-2*i; a[n-1][2*i]=a[n-2*i-1][n-1]=a[n-2*i-2][n-1]=s; } swap(a[0][n-1],a[0][n]),swap(a[1][n-1],a[1][n]); a[n-2][n-1]=a[n-1][n-1]=a[n-1][0]=n; a[n-2][n]=a[n-1][n]=1;a[0][n]=a[1][n]=2; a[1][n]=1,a[n-1][0]=2,a[n-1][n]=n; for(int i=0;i<n;i++){ for(int j=0;j<n+1;j++){ cout<<a[i][j]<<' '; }cout<<"\n"; } } } }

C - First Come First Serve

不如滚去颓废

现在感觉心情好一点了,应该可以卷一道题,感谢音乐的力量

C i = 0 / 1 C_i=0/1 Ci=0/1表示选的是 A i / B i A_i/B_i Ai/Bi,问题相当于数本质不同的 { C i } \{C_i\} {Ci}数目,这里的本质不同指的是生成的排列 P P P不同。

然后对于小数据手玩一下,可以得出一个看着很对的结论:若 C 1 C_1 C1, C 2 C_2 C2是本质相同的,那么 min ⁡ ( C 1 , C 2 ) \min(C_1,C_2) min(C1,C2)也是相同的。这里的 min ⁡ \min min就是按位取最小值的意思。所以我们对于一个等价类取最小的那个作为代表元。

我们可以尝试来数 { C i } \{C_i\} {Ci}。显然 C i = 0 C_i=0 Ci=0的位置都是好的,对于 C i = 1 C_i=1 Ci=1的位置,显然 A i A_i Ai比之前的 C j = 0 C_j=0 Cj=0的位置都高,并且要相对顺序发生变化的话,就要存在一个 C j = 1 ( j < i ) C_j=1(j<i) Cj=1(j<i)使得 B j > A i B_j>A_i Bj>Ai,或者存在一个 C j = 0 ( j > i ) C_j=0(j>i) Cj=0(j>i)使得 A j < B i A_j<B_i Aj<Bi

d p dp dp部分有点复杂。这种有限制的 d p dp dp如果处理的不好的话就会很复杂 让我们先冷静一下,设 r i r_i ri表示最大的满足 A j < B i A_j<B_i Aj<Bi的点,那么 i i i对后面的限制相当于 [ i : r i ] [i:r_i] [i:ri]中必须有一个为 0 0 0,那么取 r i r_i ri最小的那个一定就是最紧的限制,又因为 r i r_i ri是单增的,所以我们似乎要维护第一个对后面有限制的那个位置,这样就没办法优化了。

倒着来会不会好一点?这种题就是要多尝试 我看到有人用这种方法过的,但是感觉很神奇,难道正着和倒着做真的有什么非常本质的区别吗?

正解非常脑洞。反正我是想不到 我们考虑 i i i不合法时的情况 ,设 l j l_j lj表示 B j > A i B_j>A_i Bj>Ai的最小的点,那么 [ l j : i ) [l_j:i) [lj:i)都必须全为 0 0 0;设 r j r_j rj表示 A j < B i A_j<B_i Aj<Bi的最大的点,那么 ( i : r j ] (i:r_j] (i:rj]都必须全为 1 1 1。然后我们容斥不合法的那些位置,如果 [ l i : r i ] ∩ [ l j : r j ] ≠ ∅ [l_i:r_i]\cap [l_j:r_j]\ne \varnothing [li:ri][lj:rj]=那么方案数为 0 0 0 这个结论可以猜,因此被固定的位置数目就是所有限制区间长度之和,设 f i f_i fi表示考虑前 i i i个位置时的容斥系数之和,如果 i i i有限制那么 f i = ∑ R j < L i f j 2 L i − R i − 1 ( − 1 ) f_i=\sum_{R_j<L_i}f_j2^{L_i-R_i-1}(-1) fi=Rj<Lifj2LiRi1(1),用树状数组维护会多一个 log ⁡ \log log,如果按 R i R_i Ri排序再 d p dp dp就能做到 O ( n ) O(n) O(n)了。当然都能过

#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define db double using namespace std; const int mod=998244353; const int N=5e5+5; int n,a[N],b[N],L[N],R[N]; ll bit[N],f[N],pw[N],invpw[N],inv2=(mod+1)/2,sum=1; int s[N],cnt; void upd(ll x,ll y){ for(;x<=n;x+=x&-x)bit[x]=(bit[x]+y)%mod; } ll ask(ll x){ ll tot(0); for(;x;x-=x&-x)tot=(tot+bit[x])%mod; return tot; } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n;pw[0]=invpw[0]=1;for(int i=1;i<=n;i++)pw[i]=pw[i-1]*2%mod,invpw[i]=invpw[i-1]*inv2%mod; for(int i=1;i<=n;i++)cin>>a[i]>>b[i]; for(int i=1;i<=n;i++){ int l=1,r=i-1,res=i; while(l<=r){ int mid=l+r>>1; if(b[mid]>a[i])res=mid,r=mid-1; else l=mid+1; }L[i]=res; l=i+1,r=n,res=i; while(l<=r){ int mid=l+r>>1; if(a[mid]<b[i])res=mid,l=mid+1; else r=mid-1; }R[i]=res; f[i]=-(ask(L[i]-1)+1)*invpw[R[i]-L[i]+1]%mod; upd(R[i],f[i]); sum=(sum+f[i])%mod; }sum=sum*pw[n]%mod; cout<<(sum+mod)%mod; }

D - Almost Multiplication Table

感觉题解的做法挺有道理的,但是不太清楚这样为什么一定是对的。不过 { X i , Y i } \{X_i,Y_i\} {Xi,Yi}为正整数的条件可以利用一下,可能要证明一下它是收敛的吧。

E - Increment or XOR

这玩意状态数咋分析啊


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530025.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2022-02-24 【题解】「BZOJ4504」K个串
点击右上角即可分享
微信分享提示