【学习笔记】AGC061
开个坑然后慢慢填
我为什么要做题,不如颓废
A - Long Shuffle
这题好难啊 是我太菜了吗
当 
     
      
       
       
         n 
        
       
      
        n 
       
      
    n是偶数时,我们发现只会在 
     
      
       
        
        
          A 
         
         
         
           2 
          
         
           i 
          
         
           − 
          
         
           1 
          
         
        
       
      
        A_{2i-1} 
       
      
    A2i−1和 
     
      
       
        
        
          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,n−2)+(3,n)(这里的加法表示操作拼接的意思),接下来的尝试非常脑洞:如果 A 2 i − 1 A_{2i-1} A2i−1和 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} A2i−1和 A 2 i A_{2i} A2i交换当且仅当 ( n / 2 − 1 i − 1 ) \binom{n/2-1}{i-1} (i−1n/2−1)为奇数。
对于 n n n为奇数的情况,显然我们可以看成 ( 1 , n − 1 ) + ( 2 , n ) (1,n-1)+(2,n) (1,n−1)+(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<Lifj2Li−Ri−1(−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
这玩意状态数咋分析啊

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号