1. 程式人生 > >【刷題】BZOJ 2190 [SDOI2008]儀仗隊

【刷題】BZOJ 2190 [SDOI2008]儀仗隊

AD 100% puts IT gist logs www sample blog

Description

作為體育委員,C君負責這次運動會儀仗隊的訓練。儀仗隊是由學生組成的N * N的方陣,為了保證隊伍在行進中整齊劃一,C君會跟在儀仗隊的左後方,根據其視線所及的學生人數來判斷隊伍是否整齊(如下圖)。

技術分享圖片

現在,C君希望你告訴他隊伍整齊時能看到的學生人數。

Input

共一個數N。

Output

共一個數,即C君應看到的學生人數。

Sample Input

4

Sample Output

9

HINT

【數據規模和約定】   對於 100% 的數據,1 ≤ N ≤ 40000

Solution

以前看這題,無從下手
現在看這題,毫無意義
由於這個什麽人在隊列的左下角,所以我們先把第一列和最後一行去掉,剩下的變成一個矩陣

然後對於這個矩陣
\(ans'=\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)=1]\)
\(\ \ \ \ \ \ \ \ =\sum_{i=1}^n\mu(i)(\lfloor \frac{n}{i}\rfloor )^2\)
然後加上原來的最後一行和第一列的貢獻,就是加2
答案就是\(ans=ans'+2\)
當然,這種做法要特判一下,因為我們剔掉了一行一列,那麽當 \(n=1\) 的時候,答案特判,為0

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXN=40000+10; int n,vis[MAXN],prime[MAXN],cnt,s[MAXN],mu[MAXN]; ll res=0; template<typename T> inline void read(T &x) { T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while
(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char c='\0') { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(c!='\0')putchar(c); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} inline void init() { memset(vis,1,sizeof(vis)); vis[0]=vis[1]=1; mu[1]=1; for(register int i=2;i<MAXN;++i) { if(vis[i]) { prime[++cnt]=i; mu[i]=-1; } for(register int j=1;j<=cnt&&i*prime[j]<MAXN;++j) { vis[i*prime[j]]=0; if(i%prime[j])mu[i*prime[j]]=-mu[i]; else break; } } for(register int i=1;i<MAXN;++i)s[i]=s[i-1]+mu[i]; } int main() { init(); read(n); if(n<=1) { puts("0"); return 0; } n--; for(register int i=1;;) { if(i>n)break; int j=n/(n/i); res+=1ll*(n/i)*(n/i)*(s[j]-s[i-1]); i=j+1; } write(res+2,'\n'); return 0; }

【刷題】BZOJ 2190 [SDOI2008]儀仗隊