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 }

 

posted @ 2021-07-20 17:11  praying_cqf  阅读(152)  评论(0编辑  收藏  举报