1. 程式人生 > >10.3 廣州集訓 Day2

10.3 廣州集訓 Day2

etc ctype 取消 char 莫比烏斯反演 人才 多少 func 所有

T1

 1 數學課
程序文件名: number.c/cpp/pas
輸入文件: number.in
輸出文件: number.out
時間限制: 1s
空間限制: 256Mb

題目描述  

數學課上,老師在黑板上寫了n個數,然後讓大家做一個遊戲:每次擦掉黑板上的兩個數,然後在黑板上寫下這兩個數的乘積加一,直到最後只有一個數。同學們做了幾次這個遊戲之後,發現最終剩下的數大小不一。同學們十分好奇,但老師說:“如果你們能保證剩下的數比我玩的時候剩下的數要小或者相等,那我就告訴你們原因。”同學們現在十分想知道原因,你能幫幫他們嗎?

輸入格式


第一行有一個正整數n,代表數字的個數。
下一行有n個正整數a1; a2; :::; an,表示老師在黑板上寫下的數。

輸出格式


一個數,表示同學們最後應該剩下的數。對109 + 7取模。


樣例

  輸入 輸出
  3 15
  2 2 3
樣例解釋:先將2和3擦掉,寫下7,再將7和2擦掉,寫下15。


數據範圍

  對於20%的數據,n≤8 ,????≤10

  對於40%的數據,n≤8

  對於100%的數據,n≤200 ,????≤10^9

Solution:

  簡單模擬+貪心。

  我們可以證明每次去兩個最大的數相乘一定比其余做法優。

  可以通過二叉樹說明。

  技術分享

  假設a為左圖最小值,則左圖->右圖可以發現右圖更小。

  進行類似操作,可以發現最小值通過被替換一直會留在二叉樹中,而最大值則會被擦去。

  也就是說,最小值總是最後擦去,而最大值被不斷刪除。

  以此類推,每次的做法就是取兩個最大值相乘。

  該做法是O(nlogn)。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define MODE 1000000007
 4 #define MAXN 205
 5 #define ll long long
 6 using namespace std;
 7 int a[MAXN];
 8 int n;
 9 ll ans=0;
10 inline int
read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} 13 while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} 14 return x*f; 15 } 16 bool cmp(int x,int y){return x>y;} 17 int main(){ 18 freopen("number.in","r",stdin); 19 freopen("number.out","w",stdout); 20 n=read(); 21 for(int i=1;i<=n;i++) a[i]=read(); 22 sort(a+1,a+n+1,cmp); 23 //for(int i=1;i<=n;i++) printf("a[i]=%d\n",a[i]); 24 ans=a[1]; 25 for(int i=2;i<=n;i++){ 26 ans*=a[i];ans+=1;ans%=MODE; 27 } 28 printf("%d",ans); 29 return 0; 30 }

T2

遺傳病(disease,2s,256M)

【題目描述】

眾所周知,近親結婚的後代患遺傳病的概率會大大增加。如果某一基因按常染色體隱性遺傳方式,其子女就可能因為是突變純合子而發病。因此,近親婚配增加了某些常染色體隱性遺傳疾病的發生風險。

現在有n個人,每個人都有一個遺傳特征值a_i,假設第i個人和j個人結婚,那麽風險系數為gcd?(a_i,a_j),法律規定只有風險系數為1時兩個人才能結婚。

F同學開了一個婚姻介紹所,這n個人可能會來登記,當然也有可能登記後取消,也有可能取消後再登記。F同學的任務就是,求出當前所有登記的人中,有多少對人是可以結婚的。

剛開始所有人都沒有登記。

為出題需要,不考慮性別,基因突變和染色體變異等QAQ。

【輸入格式】

從disease.in中讀入。

第一行兩個整數n和q,n表示人數,q表示登記和登出的總次數。

第二行n個整數a_1,a_2,…,a_n,意義如上所述。

接下來q行,每行一個整數x。如果當前第x個人沒有登記,那麽第x個人登記;如果當前第x個人已經登記了,那麽其取消登記。

【輸出格式】

輸出到disease.out中。

一共q行,第i行表示第i個操作後,當前所有登記的人中有多少對人是可以結婚的。

【樣例一輸入】

5 6

1 2 3 4 6

1

2

3

4

5

1

【樣例一輸出】

0

1

3

5

6

2

【子任務】

30%數據,1<=n,q<=1000

100%數據,1<=n,q<=100000,1<=ai<=500000

Solution: 

  本題考察容斥原理。

  30%數據,每加入或刪除一個數,掃一下已經登記的人求一下gcd即可,時間復雜度O(n^2)

  100%數據,考慮容斥原理。

  比如加入一個數30,那麽60的質因數集合為{2,3,5}(重復的去掉)

  兩個數互質等價於質因數集合交集問空集。

  記|S|為當且已登記的人中質因數集合的子集有S的人數,其中S是一個質因數集合

  特別地,記|{1}|=當前已登記的人數

  與30互質的個數=|{1}|-|{2}|-|{3}|-|{5}|+|{2,3}|+|{2,5}|+|{3,5}|-|{2,3,5}|

  因為2*3*5*7*11*13*17=510510>500000,所以每個數最多只有6個質因數(重復的去掉)

  2^6=64,時間復雜度為O(64n)。

Other:

  還沒有A。

  本題也是莫比烏斯反演。

  

  1 //std
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cassert> 
  5 #include<iostream>
  6 #include<fstream>
  7 #include<algorithm>
  8 #include<cstring>
  9 #include<string>
 10 #include<cmath>
 11 #include<queue>
 12 #include<stack>
 13 #include<map>
 14 #include<utility>
 15 #include<set>
 16 #include<bitset>
 17 #include<vector>
 18 #include<functional>
 19 #include<deque>
 20 #include<cctype>
 21 #include<climits>
 22 #include<complex>
 23 #include<bits/stdc++.h>
 24 #include<ctime>
 25 #include<ext/rope>
 26 
 27 using namespace __gnu_cxx; 
 28 using namespace std;
 29 
 30 typedef long long LL;
 31 typedef double DB;
 32 typedef pair<int,int> PII;
 33 typedef pair<DB,DB> PDD;
 34 typedef complex<DB> CP;
 35 typedef vector<int> VI;
 36 
 37 #define mmst(a,v) memset(a,v,sizeof(a))
 38 #define mmcy(a,b) memcpy(a,b,sizeof(a))
 39 #define fill(a,l,r,v) fill(a+l,a+r+1,v)
 40 #define re(i,a,b)  for(i=(a);i<=(b);i++)
 41 #define red(i,a,b) for(i=(a);i>=(b);i--)
 42 #define fi first
 43 #define se second
 44 #define mp(a,b) make_pair(a,b)
 45 #define pb(a) push_back(a)
 46 #define two(k) (1<<(k))
 47 #define SZ(x) (int(x.size()))
 48 #define all(x) (x).begin(),(x).end()
 49 #define ire(i,v,x) for(i=0,v=i<SZ(x)?x[i]:0;i<SZ(x);v=x[++i])
 50 #define ls (rt<<1)
 51 #define rs (rt<<1|1)  
 52 #define MID ((l+r)>>1)
 53 
 54 template<class T>inline T sqr(T x){return x*x;}
 55 template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
 56 template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
 57 
 58 inline int sgn(DB x){if(abs(x)<1e-9)return 0;return(x>0)?1:-1;}
 59 const DB Pi=acos(-1.0);
 60 
 61 //void enlargestack(){int size=256<<10;char *p=(char*)malloc(size)+size;__asm__("movl %0, %%esp\n"::"r"(p));}
 62 
 63 int gint()
 64   {
 65         int res=0;bool neg=0;char z;
 66         for(z=getchar();z!=EOF && z!=- && !isdigit(z);z=getchar());
 67         if(z==EOF)return 0;
 68         if(z==-){neg=1;z=getchar();}
 69         for(;z!=EOF && isdigit(z);res=(res<<3)+(res<<1)+z-0,z=getchar());
 70         return (neg)?-res:res; 
 71     }
 72 LL gll()
 73   {
 74       LL res=0;bool neg=0;char z;
 75         for(z=getchar();z!=EOF && z!=- && !isdigit(z);z=getchar());
 76         if(z==EOF)return 0;
 77         if(z==-){neg=1;z=getchar();}
 78         for(;z!=EOF && isdigit(z);res=res*10+z-0,z=getchar());
 79         return (neg)?-res:res; 
 80     }
 81     
 82 const int maxn=210000;
 83 const int maxm=510000;
 84 
 85 int n,q,m;
 86 int a[maxn];
 87 int cnt,flag[maxm],prime[maxm],p[maxm];
 88 vector<int> b[maxn];
 89 int in[maxn];
 90 int table[maxm];
 91 LL res;
 92 
 93 void init()
 94   {
 95       int i,j;
 96       re(i,2,m)
 97         {
 98             if(!flag[i])prime[++cnt]=i;
 99                 for(j=1;j<=cnt && i*prime[j]<=m;j++)
100                   {
101                       flag[i*prime[j]]=1;
102                         p[i*prime[j]]=prime[j];
103                         if(i%prime[j]==0)break;
104                     }
105         }
106       re(i,1,n)
107         {
108             int x=a[i];
109             while(x!=1)
110               {
111                   int t=flag[x]?p[x]:x;
112                   b[i].pb(t);
113                   while(x%t==0)x/=t;
114               }
115         }
116   }
117 
118 void dfs(int x,int k,int mult,int f)
119   {
120       if(k==SZ(b[x]))
121         {
122             res+=in[x]==1?table[mult]*in[x]*f:(table[mult]-1)*in[x]*f;
123             table[mult]+=in[x];
124             return;
125         }
126       dfs(x,k+1,mult*b[x][k],-f);
127       dfs(x,k+1,mult,f);
128   }
129 
130 int main()
131   {
132       freopen("disease.in","r",stdin);
133       freopen("disease.out","w",stdout);
134       int i;
135       n=gint();q=gint();
136       re(i,1,n)a[i]=gint(),upmax(m,a[i]);
137       init();
138       fill(in,1,n,1);
139       while(q--)
140         {
141             int x=gint();
142             dfs(x,0,1,1);
143             in[x]=-in[x];
144             printf("%I64d\n",res);
145         }
146       return 0;
147   }

T3

瓜分領土(2s,512MB)

石頭、剪刀和布鬧別扭了,他們要分家。

他們生活在一個離散的一維空間裏,簡單點說,他們擁有在一條直線上的N間房子,每間房子有一個風水值(有正有負)。

然後,他們決定將這N間房子分成非空的三個連續段,從左到右數,第一段的房子全部屬於石頭,第二段的房子全部屬於剪刀,第三段的房子全部屬於布。

由於他們希望公平,並且又由於剪刀是他們的老大哥,他們決定根據這些條件制定了一個評判標準:

設石頭擁有的房子的風水值和為a,剪刀擁有的房子的風水值和為b,布擁有的房子的風水值和為c,剪刀擁有n間房子。

那麽通過給定一個參數x。

那麽,這種分配的合理值就是max(a,b,c)-min(a,b,c)+x*n.

合理值越小,表示這種分配越合理。

因此,我們現在就是要求出這個最小的合理值。

輸入格式

第一行一個正整數N。

第二行有N個整數,表示房子的風水值,按從左到右的順序給出。

第三行一個整數x。

輸出格式

一行一個整數,表示最小的合理值。

輸入樣例:

4

1 1 1 1

-1

輸出樣例:

-1

數據範圍:

對於30%的數據,N<=10.

對於70%的數據,N<=1000.

對於100%的數據,N<=100000,保證所有運算結果在long long範圍內。

Solution:

  線段樹+二分+離散+枚舉+數學結論。

  留坑。以及正解寫掛60<暴力O(n^2)的慘案。

10.3 廣州集訓 Day2