新賽道-2024.8 CSP-J組月賽-T1總結

谦谦2022發表於2024-09-01

題面:

王老師 最近做了一道經典問題《翻紙牌》

現在 王老師 有 n 張牌,編號分別為 1,2,3n,每張牌一開始都是背面朝上的

現在他要進行 n 輪操作,第 i 輪操作時候,他會將所有編號是 i 的倍數的牌正反翻面

現在 王老師 想知道,當他進行完 n 輪操作以後,所有正面朝上的牌的編號總和是多少

因為數字可能很大,所以請你將答案對 109+7 取模

對於 30% 的資料:1n106

對於 60% 的資料:1n1014

對於 100% 的資料:1n1018

從題中可知將n翻面的只有n的因子,而翻到正面的數字的因子個數一定是奇數,也就是完全平方數,再套入公式:n*(n+1)*(2*n+1)/6即可,但資料量為1e18,這麼算會爆long long (我就是這麼寫掛的。。),所以需要用到特殊處理,首先,我們知道n*(n+1)%2==0,所以可以先算n*(n+1)/2,剩下的/3分兩種情況討論

設v=sqrt(n),x=v*(v+1)/2

1.若x%3==0,那麼直接先將x/3%mod*(2*v+1)%mod;

2.否則把/3丟給(2*v+1):x%mod*((2*v+1)/3)%mod

程式碼:

#include <bits/stdc++.h>
using namespace std;
const unsigned long long mod=1e9+7;
unsigned long long n;
int main(){
  //freopen("card.in","r",stdin);
  //freopen("card.out","w",stdout);
  ios::sync_with_stdio(0);
  cin.tie(0);cout.tie(0);
  cin>>n;
  unsigned long long op=sqrt(n);
  unsigned long long ans=op*(op+1)/2;
  if(ans%3==0)cout<<ans/3%mod*(2*op+1)%mod;
  else cout<<ans%mod*((2*op+1)/3)%mod;
  return 0;
}

總結:在做題時需觀看資料量判斷其會不會爆,在進行處理,我在估資料量時還是比較弱,以後在打程式碼前應估計在中途會不會爆,再寫程式碼。