7.20杭電多校第一場


過了6題

我開局秒了1001,隊友讀題1005,我也秒了,幫忙想了一部分1008,寫了1009,想了一點點1010,想了一部分1006(但隊友已經打了,太猛了

1001

題意:求n%(1~n)的或和

n<=10^12

題解:

當模數是n/2以上時,0~n/2-1都會出現一次,當模數是n/2以下時,結果也不超過n/2-1

所以答案就是模出來的最大結果的二進制補全。

代碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     int t;
 6     scanf("%d",&t);
 7     while (t)
 8     {
 9         t--;
10         long long n;
11         scanf("%lld",&n);
12         if (n&1) n=(n-1)/2;else 
13         n=n/2-1;
14         long long pty=1;
15         while (pty<=n) pty*=2;    
16         printf("%lld\n",pty-1);
17     }
18 }

1005

題意:

n-1個點,編號從2開始,邊權是兩點編號的LCM,求生成樹

n<=10^7

題解:

如果i是合數,找個因子連邊,新增答案就是i

如果是質數,只能找2或者自己的2倍連邊,新增答案是2*i

預處理即可

代碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int zs[5000000],p[10000010];
 4 long long f[10000010];
 5 int main()
 6 {
 7     int sk=0;
 8     for (int i=2;i<=10000000;i++) 
 9     {
10         if (!p[i]) zs[++sk]=i;
11         for (int j=1;j<=sk&&i*zs[j]<=10000000;j++)
12         {
13             p[i*zs[j]]=1;
14             if (i%zs[j]==0) break;
15         }
16     }
17     f[2]=0;
18     for (int i=3;i<=10000000;i++) if (p[i]) f[i]=f[i-1]+i;else f[i]=f[i-1]+2*i;
19     int t;
20     scanf("%d",&t);
21     while (t)
22     {
23         t--;
24         int n;
25         scanf("%d",&n);
26         printf("%lld\n",f[n]);    
27     }
28 }

1008

題意:

一個n*m的矩陣,要找一個最大的子矩陣滿足每列不下降

n,m<=2000

題解:

設p[i][j]表示從(i,j)出發最長的不下降長度

再枚舉行,用單調棧做類似最大矩陣就可以了

代碼:

 1 #include<bits/stdc++.h>
 2 #define LL long long 
 3 #define N 2050
 4 #define MIN 0xc0c0c0c0
 5 using namespace std;
 6 int a[2050][2050],p[2050][2050],ans = MIN,maxx  = 0;
 7 
 8 void ww()
 9 {
10     ans = 0;
11     int n,m;
12     scanf("%d%d",&n,&m);
13     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]),p[i][j]=1;
14     for (int i=n-1;i>=1;i--) for (int j=1;j<=m;j++) if (a[i][j]<=a[i+1][j]) p[i][j]=p[i+1][j]+1;
15     
16 //    for (int i=1;i<=n;i++) 
17 //    {
18 //        cout<<endl;
19 //        for (int j=1;j<=m;j++) 
20 //        {
21 //            cout<<p[i][j]<<" ";
22 //        }
23 //    }
24 //    cout<<endl;
25     
26     int h[N],l[N],r[N],q[N];
27     for(int z=1;z<=n;z++)
28     {
29         maxx = 0;
30         int tt = 0;
31         q[0] = 0;
32         p[z][0] = p[z][m+1] = -1;
33         for(int i=1;i<=m;i++)
34         {
35             while( p[z][i] <= p[z][ q[tt] ] ) tt--;
36             l[ i ] = q[tt];
37             q[ ++tt ] = i;
38         }
39         tt = 0;
40         q[0] = m+1;
41         for(int i=m;i>=1;i--)
42         {
43             while( p[z][i] <= p[z][ q[tt] ] ) tt--;
44             r[i] = q[tt];
45             q[ ++tt ] = i;
46         }
47         for(int i=1;i<=m;i++)
48         {
49             maxx = max( maxx , p[z][i]*( r[i]-l[i]-1 ) );
50         }
51         ans = max( maxx , ans );
52     }
53     printf("%d\n",ans);
54     
55 }
56 int main()
57 {
58     //freopen("in.txt","r",stdin);
59     int t;
60     scanf("%d",&t);
61     while (t)
62     {
63         t--;
64         
65         ww();    
66     }
67 }

1009

題意:

一個n個點的無向帶權聯通圖,在給定數D和K的情況下,如果滿足以下條件:

1.點被分為非空的k組

2.同一組內的兩點之間存在至少一條路徑,路徑上的最大權值小於等於D

3.不同組內的兩點不存在任何一條路徑,路徑上的最大權值小於等於D

這樣的圖被稱為KD圖

給出n和K,求最小的D使得圖是KD圖

n<=10^5

題解:

枚舉答案D,刪去所有大於D的邊,剩余圖聯通塊如果有恰好k個,則D是一個合法答案。

發現這個過程其實就是克魯斯卡爾求最小生成樹的過程,只不過相同邊權需一次加入,再判斷聯通塊的個數與k的關系

代碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct aa
 4 {
 5     int x,y,z;    
 6 }e[500050];
 7 bool cmp(aa x,aa y)
 8 {
 9     return x.z<y.z;    
10 }
11 int f[100010];
12 int get(int x)
13 {
14     if (f[x]==x) return x;
15     return f[x]=get(f[x]);
16 }
17 void ww()
18 {
19     int n,m,k;
20     scanf("%d%d%d",&n,&m,&k);
21     for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
22     sort(e+1,e+m+1,cmp);
23     for (int i=1;i<=n;i++) f[i]=i;
24     e[m+1].z=0;
25     if (n==k)
26     {
27         printf("0\n");
28         return;    
29     }
30     for (int i=1;i<=m;i++)
31     {
32         int xx=get(e[i].x),yy=get(e[i].y);
33         if (xx!=yy) n--;
34         f[xx]=yy;
35         if (e[i].z!=e[i+1].z&&n==k)     
36         {
37             printf("%d\n",e[i].z);
38             return;    
39         }
40     }
41     printf("-1\n");
42 }
43 int main()
44 {
45     int t;
46     scanf("%d",&t);
47     while (t)
48     {
49         t--;
50         ww();
51     }
52 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM