2 条题解

  • 0
    @ 2026-8-30 22:02:38

    坏了,这一下真给我难道了。(题目标签应该加一个数学)

    这题最为关键的就是发现这么一个性质:给出的棋盘其实根本不重要,既然任意两个棋子不在同一行也不在同一列,那我们完全就可以把整个棋盘打乱重拍,强制令第 ii 行的障碍在第 ii 列,那么原问题就变成了如下问题:

    求出有多少个排列,使得第 ii 个位置不能为 ii

    这是一个经典的错排问题,我们定义 f(i)f(i) 为前 ii 个数的放置方案,显然,对于第 ii 个数而言,除了 ii 都能放,所以有 i1i-1 种可能。假设其放在了位置 xx 上,则 xx 可以放在 ii 上,此时转化为 f(i2)f(i-2),也可以放在别的位置上,此时转化为 f(i1)f(i-1),递推公式就是:

    f(i)=(n1)×(f(i2)+f(i1))f(i)=(n-1)\times(f(i-2)+f(i-1))

    最后写个高精度就可以了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    struct num{//高精度 
    	string nu;
    	num operator +(const num &ano)const{
    		string a=nu,b=ano.nu;
    		if(a.size()>b.size())swap(a,b);
    		int l1=a.size(),l2=b.size();
    		//  0 1 2 3 l1=4
    		//0 1 2 3 4 l2=5
    		string ans;
    		int ji=0;
    		for(int i=l2-1;i>=l2-l1;i--){
    			ans=char((a[i-l2+l1]-'0'+b[i]-'0'+ji)%10+'0')+ans;
    			ji=(a[i-l2+l1]-'0'+b[i]-'0'+ji)/10;
    		}
    		for(int i=l2-l1-1;i>=0;i--){
    			ans=char((b[i]-'0'+ji)%10+'0')+ans;
    			ji=(b[i]-'0'+ji)/10;
    		}
    		if(ji)ans='1'+ans;
    		return (num){ans};
    	}
    	num operator *(const int &ano)const{
    		int ji=0;
    		string ans; 
    		for(int i=nu.size()-1;i>=0;i--){
    			ans=char(((nu[i]-'0')*ano+ji)%10+'0')+ans;
    			ji=((nu[i]-'0')*ano+ji)/10;
    		}
    		if(ji){
    			ans=to_string(ji)+ans;
    		}
    		return (num){ans};
    	} 
    };
    num dp[205];
    int main(){
    	int n;
    	cin>>n;
    	dp[1].nu="0",dp[2].nu="1";
    	for(int i=3;i<=n;i++){
    		dp[i]=(dp[i-1]+dp[i-2])*(i-1);
    	}
    	cout<<dp[n].nu;
    	return 0;
    } 
    
    • 0
      @ 2025-10-8 17:10:46
      #include<bits/stdc++.h>//qkw
      using namespace std;
      //#define int long long
      struct node
      {
          int a[1010],len;
          node()
          {
             len=1;
             memset(a,0,sizeof(a));
          }
      };
      node dp[210];
      node operator+(node n1,node n2)
      {
          node no;no.len=max(n1.len,n2.len);
          for(int i=1;i<=no.len;i++)no.a[i]=n1.a[i]+n2.a[i];
          for(int i=1;i<=no.len;i++)no.a[i+1]+=no.a[i]/10,no.a[i]%=10;
          int i=no.len;
          while(no.a[i+1]>0)
          {
              i++;
              no.a[i+1]+=no.a[i]/10;
              no.a[i]%=10;
          }
          while(no.a[i]==0&&i>1)i--;
          no.len=i;
          return no;
      }
      node operator-(node n1,node n2)//默认n1比n2大 
      {
          node no;
          no.len=n1.len;
           
          for(int i=1;i<=no.len;i++) no.a[i]=n1.a[i]-n2.a[i];
        
          for(int i=1;i<=no.len;i++)if(no.a[i]<0)no.a[i+1]--,no.a[i]+=10;
         
          int i=no.len;
          while(no.a[i+1]>0)
          {
              i++;
              no.a[i+1]+=no.a[i]/10;
              no.a[i]%=10;
          }
          while( (no.a[i]==0) && (i>1)) i--;
          no.len=i;
           
          return no;
      }
      node operator*(node n1,int x)
      {
          node no;
          no.len=n1.len;
           
          for(int i=1;i<=no.len;i++) no.a[i]=n1.a[i]*x;
           
          for(int i=1;i<=no.len;i++)
          {
              no.a[i+1]+=no.a[i]/10;
              no.a[i]%=10;
          }
           
          int i=no.len;
          while(no.a[i+1]>0)
          {
              i++;
              no.a[i+1]+=no.a[i]/10;
              no.a[i]%=10;
          }
          while((no.a[i]==0) && (i>1)) i--;
          no.len=i;
           
          return no;
      }
      signed main()
      {
          int n;cin>>n;
          dp[2].a[1]=1;
          for(int i=3;i<=n;i++)
          {
              dp[i]=dp[i-1]*i;
              node sum;sum.a[1]=1;
              if(i%2)dp[i]=dp[i]-sum;
              else dp[i]=dp[i]+sum;
          }
          for(int i=dp[n].len;i>=1;i--)printf("%d",dp[n].a[i]);
          return 0;
      }
      
      • 1

      信息

      ID
      6228
      时间
      1000ms
      内存
      256MiB
      难度
      8
      标签
      递交数
      109
      已通过
      19
      上传者