1. 程式人生 > >10.25 AHSOFNU 校內模擬

10.25 AHSOFNU 校內模擬

矩陣 font urn 決定 個人 logs 暴力 數據 scan

//今天泉七考我們的題 感覺大家都很巨大啊~

切題(problem)

【問題描述】
  小 Z 和小 G 都是切題好手,他們經常搶著切題,今天他們已經 決定好了 n 道要切的題目並準備按照順序切掉這些題。每道題都有一個難度值 di,兩個人都想自己切掉的題難度值之和最大,但他們又不屑於切對方切過的題,於是兩人制定了如下規則:一開始,決定誰切下一道題的權利在作為老大的小 Z 手裏,擁有這個權利的人可以指定誰切下一道題,當被指定的那個人切完題後,這個權利會轉移到沒切這道題的那個人手上(可以是自己)。兩人都很強,所以他們總是進行最優的決策以使自己切到的題難度值之和最大。F 大爺想知道他們最後各自切的題的難度值之和。

【輸入格式】
  第一行一個正整數 n,表示題數。
  接下來 n 個正整數 di,依次表示第 i 道要切的題的難度值。

【輸出格式】
  輸出兩個用空格隔開的整數,分別表示小 Z 和小 G 切掉的題的難度值之和。

【樣例輸入】
  4
  2 3 3 3

【樣例輸出】
  6 5

【數據範圍】
  對於 20%的數據,n<=5;
  對於 40%的數據,n<=50;
  對於 60%的數據,n<=500;
  對於 80%的數據,n<=5000;
  對於 100%的數據,n<=50000,di<=100。

Solution:

  由於權利在小 Z 或小 G 手上,而且轉移只有取與不取,我們可以考慮DP。

  每個狀態向後轉移只有兩種,我們可以倒著DP,dp[ i ] [0/1]表示還剩下 i 道題,考慮小 Z 之後的收益之和,所以小 Z 會對兩者去max,小 G 會對兩者取min。

 1 #include<cstdio>
 2 #define MAXN 50005
 3 using namespace std;
 4 int f[2][MAXN],d[MAXN],sum=0;
 5 inline int Max(int a,int b){return a>b?a:b;}
 6 inline int Min(int a,int b){return a<b?a:b;}
 7 int
main(){ 8 freopen("problem.in","r",stdin); 9 freopen("problem.out","w",stdout); 10 int n;scanf("%d",&n); 11 for(int i=1;i<=n;i++) scanf("%d",&d[i]),sum+=d[i]; 12 for(int i=n;i>=1;i--) { 13 f[0][i]=Max(f[0][i+1],f[1][i+1]+d[i]);//small Z 14 f[1][i]=Min(f[0][i+1],f[1][i+1]+d[i]);//small G 15 } 16 printf("%d %d",f[0][1],sum-f[0][1]); 17 return 0; 18 }

開車(car)

【問題描述】
  老司機小 Q 要在一個十字路口指揮車隊開車,這個十字路口可 以描述為一個 n*n 的矩陣,其中第 2 行到第 n-1 行都各有一道橫向車 道,第 2 列到第 n-1 列都各有一條縱向車道。飆車開始前,小 Q 可以 在每條車道的兩端(橫向車道為從左到右第 1 格和第 n 格,縱向車道 為從上到下的第 1 格和第 n 格)安置一輛大卡車。安置結束後,小 Q可以下令讓所有大卡車同時向車道的另一端行駛,所有的卡車速度都相同。小 Q 要合理安排這些卡車,使得它們在行駛過程中不會相撞;另外一些格子上有小 C 放置的巨石,這些格子不能通過卡車。小 Q希望安置的卡車最多,請你求出最多的卡車數。

【輸入格式】
  第一行兩個非負整數 n 和 m,分別表示十字路口大小和巨石數量。
  接下來 m 行,每行兩個正整數 xi,yi,表示在第 xi 行第 yi 列有一個巨石。

【輸出格式】
  輸出一個整數,表示答案。

【樣例輸入】
  4 3
  3 1
  3 2
  3 3

【樣例輸出】
  1

【數據範圍】
  對於 20%的數據,n<=5;
  對於 40%的數據,n<=10;
  對於 70%的數據,n<=1000;
  對於 100%的數據,3<=n<=200000,m<=200000。

Solution:

  由於存不存在可能,無論行列都只與 n-i+1 有關,暴力枚舉即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 200005
 4 #define debug 0
 5 using namespace std;
 6 int n,m,ans=0;
 7 bool a[MAXN][2];
 8 int main(){
 9     freopen("car.in","r",stdin);
10     freopen("car.out","w",stdout);
11     scanf("%d%d",&n,&m);
12     memset(a,true,sizeof(a));
13     while(m--){
14         int x,y;scanf("%d%d",&x,&y);
15         a[x][0]=false;a[y][1]=false;
16     }
17     #if debug
18         for(int i=1;i<=n;i++) printf("%d ",a[i][0]);printf("its 0\n");
19         for(int i=1;i<=n;i++) printf("%d ",a[i][1]);printf("its 1\n");
20     #endif
21     for(int i=2;i<=n-1;i++){
22         if(a[i][0]==true) ans++; 
23         if(a[i][1]==true) ans++;
24     }
25     if(n&1) if(a[n/2+1][0]&&a[n/2+1][1]) ans--;
26     printf("%d",ans);
27     return 0;
28 } 

學習(study)

【問題描述】
  巨弱小 D 準備學習,有 n 份學習資料給他看,每份學習資料的 內容可以用一個正整數 ai 表示。小 D 如果在一天內學習了多份資料,他只能記住這些資料的內容表示成的整數的最大公約數的部分。學習若幹份資料得到的收益是小 D 記下的內容之和,也就是學習的資料 數乘上這些資料內容的最大公約數。小 D 今天準備挑一段連續的資料來學習,請你告訴他最大的收益是多少。

【輸入格式】
  第一行一個正整數 n,表示資料數。
  接下來 n 個正整數 ai,分別表示每份資料的內容。

【輸出格式】
  輸出一個整數,表示答案。

【樣例輸入】
  5
  30 60 20 20 20

【樣例輸出】
  80

【數據範圍】
  對於 20%的數據,n<=100;
  對於 40%的數據,n<=1000;
  對於 70%的數據,n<=100000;
  對於 100%的數據,n<=500000,ai<=10^9。

Solution:

  對於每個右端點,其對應的區間的gcd只有log種(gcd每次變小必然會少一個質因子,而一個數的質因子只有log個),從左向右推的同時維護每種gcd的左端點即可。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 #define MN 500000
 5 int gcd(int x,int y){return y?gcd(y,x%y):x;}
 6 int a[MN+5],p[MN+5],pn,np[MN+5],npn;
 7 int main()
 8 {
 9     freopen("study.in","r",stdin);
10     freopen("study.out","w",stdout);
11     int n,i,j,x;
12     long long ans=0;
13     scanf("%d",&n);
14     for(i=1;i<=n;++i)
15     {
16         scanf("%d",&a[i]);
17         for(j=1;j<=pn;++j)a[p[j]]=gcd(a[p[j]],a[i]);p[++pn]=i;
18         for(j=1,npn=0;j<=pn;++j)if(j==pn||a[p[j]]!=a[p[j+1]])np[++npn]=p[j];
19         for(j=1,pn=npn;j<=pn;++j)p[j]=np[j],ans=max(ans,1LL*a[p[j]]*(i-p[j-1]));
20     }
21     printf("%lld",ans);
22     fclose(stdin);fclose(stdout);return 0;
23 }

10.25 AHSOFNU 校內模擬