Acdream原创群赛3(部分题解)

比赛网址链接:http://www.acdream.net/contest.php?cid=1010

 

A题: 按位异或。讨论情况。

C题:经典广搜。先打表存储各个数的因子。

G题:可以说是规律题。常规方法nlogn肯定超时。

H题:简单的二分匹配。

I题:树形dfs。

 

题目大意:给你两个有同样多元素的集合,求一个最小的x,x异或A中所有元素的结果都落在B集合中,且形成一一映射。

解题思路:关键就在于一一映射,并且先把所有的数都转换成二进制  => A,B中元素每位对应的0和1计算出来。假设第1位, A有a0个0,a1个1,b有b1个1,b0个0,

如果a0==b0&&a1==b1  那么x对应的此位必为0,否则a0==b1&&a1==b0,x对应的此位必为1.

View Code
 1 #include <iostream>

 2 #include <cstdio>

 3 #include <algorithm>

 4 #include <cstring>

 5 using namespace std;

 6 

 7 int  a0[40], a1[40], b0[40], b1[40];

 8 int   x[40];

 9 bool flag;

10 

11 void cal()

12 {

13     for(int i=0; i<33; i++)

14     {

15         if(a0[i]==b0[i]&&a1[i]==b1[i]) x[i]=0;

16         else if(a1[i]==b0[i]&&a0[i]==b1[i]) x[i]=1;

17         else

18         {

19             flag=1;

20             break;

21         }

22     }

23 }

24 

25 int main()

26 {

27     int  n, t;

28     while(cin >> n)

29     {

30         for(int i=0; i<33; i++)

31             x[i]=a0[i]=a1[i]=b0[i]=b1[i]=0;

32         for(int i=0; i<n; i++)

33         {

34             scanf("%d",&t);

35             for(int j=0; j<33; j++)

36             {

37                 if(t%2&1) a1[j]++;

38                 else a0[j]++;

39                 t/=2;

40             }

41         }

42         for(int i=0; i<n; i++)

43         {

44             scanf("%d",&t);

45             for(int j=0; j<33; j++)

46             {

47                 if(t%2&1) b1[j]++;

48                 else b0[j]++;

49                 t/=2;

50             }

51         }

52         flag=0;

53         cal();

54         if(flag)

55         {

56             cout << -1 <<endl; continue;

57         }

58         long long ans=0, tmp=1;

59         for(int i=0; i<33; i++)

60         {

61             ans+=x[i]*tmp;

62             tmp*=2;

63         }

64         printf("%lld\n",ans);

65     }

66     return 0;

67 }

 

C

题目大意:给出两个数a,b。 a可以变成a+d,的是a的因子。求a变成b最少需要多少步。 

解题思路:先打表找出每个数的因子,注意1和本身也算。然后就是广搜了。

View Code
 1 #include <iostream>

 2 #include <cstdio>

 3 #include <queue>

 4 #include <vector>

 5 #include <cmath>

 6 #include <algorithm>

 7 #include <cstring>

 8 using namespace std;

 9 

10 const int maxn=100005;

11 int  color[maxn];

12 int  a, b, Min, ok;

13 vector<int>vt[maxn];

14 

15 struct node

16 {

17     int  t;

18     int  step;

19 };

20 

21 void init()

22 {

23     for(int i=1; i<=maxn-5; i++)

24     {

25         int t=sqrt(i+1);

26         for(int j=1; j<=t; j++)

27         {

28             if(i%j==0)

29             {

30                 vt[i].push_back(j);

31                 if(i%(i/j)==0) vt[i].push_back(i/j);

32             }

33         }

34     }

35 }

36 

37 void bfs()

38 {

39     node s,p;

40     memset(color,0,sizeof(color));

41     queue<node>q;

42     s.t=a;

43     s.step=0;

44     q.push(s);

45     while(!q.empty())

46     {

47         p=q.front();

48         q.pop();

49         if(p.t>b) continue;

50         if(p.t==b)

51         {

52             ok=1;

53             cout << p.step <<endl;

54             break;

55         }

56         for(int i=0; i<vt[p.t].size(); i++)

57         {

58             s.t=p.t+vt[p.t][i];

59             s.step=p.step+1;

60             if(s.t<=b&&!color[s.t])

61             {

62                 color[s.t]=1;

63                 q.push(s);

64             }

65         }

66     }

67 }

68 

69 int main()

70 {

71     init();

72     while(~scanf("%d%d",&a,&b))

73     {

74         ok=0;

75         bfs();

76         if(!ok) cout <<-1 <<endl;

77     }

78     return 0;

79 }

 

G:

题目大意:C[k]=∑A[i]B[j]mod(109+7)。k=max(i,j)。

解题思路:开始我用nlogn的方法求c[k],TLE。  列几项仔细分析还是有规律可寻的。

  c[k]=(a[1]+a[2]+……+a[k-1])*b[k]+b[1]+b[2]+……+b[k-1])*a[k]+a[k]*b[k]);

View Code
 1 #include <stdio.h>

 2 

 3 #define mod 1000000007

 4 #define maxn 100005

 5 long long  a[maxn], b[maxn];

 6 long long c[maxn];

 7 

 8 int main()

 9 {

10     int  n, t;

11     long long s1, s2;

12     while(scanf("%d",&n)!=EOF)

13     {

14         for(int i=0; i<n; i++)

15             c[i]=0;

16         for(int i=0; i<n; i++)

17             scanf("%lld",&a[i]);

18         for(int j=0; j<n; j++)

19             scanf("%lld",&b[j]);

20         s1=0, s2=0;

21         for(int i=0; i<n; i++)

22         {

23              c[i]=(c[i]+b[i]*s1+a[i]*s2+a[i]*b[i])%mod;

24              s1=(s1+a[i])%mod;

25              s2=(s2+b[i])%mod;

26         }

27         for(int i=0; i<n; i++)

28         {

29             if(i!=n-1)  printf("%lld ",c[i]%mod);

30             else printf("%lld\n",c[i]%mod);

31         }

32     }

33     return 0;

34 }

 

H:

题目大意:给你一些边和一些点,求最大基数匹配。

解题思路:

看袁神的解题报告说什么Em什么什么的匹配,很复杂的说。 这题有那么复杂么,怎么感觉都是水水的二分匹配呀。

View Code
 1 #include <cstdio>

 2 #include <iostream>

 3 #include <cstring>

 4 #include <algorithm>

 5 using namespace std;

 6 

 7 const int maxn=110;

 8 int  visit[maxn];

 9 int  map[maxn][maxn];

10 int  match[maxn];

11 int  n;

12 

13 bool find(int u)

14 {

15     for(int v=1; v<=n; v++)

16     {

17         if(map[u][v]&&!visit[v])

18         {

19             visit[v]=1;

20             if(match[v]==-1||find(match[v]))

21             {

22                 match[v]=u;

23                 return true;

24             }

25         }

26     }

27     return false;

28 }

29 

30 int hungary()

31 {

32    memset(match,-1,sizeof(match));

33    int ans=0;

34    for(int i=1; i<=n; i++)

35    {

36        memset(visit,0,sizeof(visit));

37        if(find(i)) ans++;

38    }

39    return ans;

40 }

41 

42 int main()

43 {

44     while(cin >> n)

45     {

46         for(int i=1; i<=n; i++)

47             for(int j=1; j<=n; j++)

48             {

49                 scanf("%d",&map[i][j]);

50             }

51         cout << hungary()/2 <<endl;

52     }

53     return 0;

54 }

 

I:

题目大意: 给你一颗树。让你删除最多的边,使得剩下的在一起的点还是偶数。

解题思路: 这题藐视困惑了我好久好久。从n以内的任意一个点开始都行,因为它是一颗树,然后进行树形dfs。把有子树是偶数个点的可以考虑删除。这里我们把要删除的边的下一个点做参照物,这样就能避免是删2个呢还是删4个或者删6个等等。

View Code
 1 #include <cstdio>

 2 #include <iostream>

 3 #include <cstring>

 4 #include <vector>

 5 #include <algorithm>

 6 using namespace std;

 7 

 8 const int maxn=100005;

 9 int  f[maxn];

10 vector<int>vt[maxn];

11 int n;

12 

13 int dfs(int u, int fa)

14 {

15     f[u]=1;

16     for(int i=0; i<vt[u].size(); i++)

17     {

18         if(vt[u][i]==fa) continue;

19         f[u]+=dfs(vt[u][i],u);

20     }

21     return f[u];

22 }

23 

24 int main()

25 {

26     int   u, v;

27     while(cin >> n)

28     {

29         for(int i=1; i<=n; i++)

30             vt[i].clear();

31         for(int i=0; i<n-1; i++)

32         {

33             scanf("%d%d",&u,&v);

34             vt[u].push_back(v);

35             vt[v].push_back(u);

36         }

37         dfs(1,1);

38         int ans=0;

39         for(int i=1; i<=n; i++)

40         {

41             if(f[i]%2==0) ans++;

42         }

43         cout << ans-1 <<endl;

44     }

45     return 0;

46 }

 

 

 

你可能感兴趣的:(题解)