【61测试】【dp】【二分】【前缀和】【树剖】

不要问我为什么昨天考的今天才贴解题报告。。

第一题:

  给定3个字符串,求它们的最长公共子序列。

解:

  考试时知道肯定是LCS的二维再加一维,用三维,可天堂有路你不走,地狱无门你偏来。。。灵机一动想出来一个方法:先记下前两个的最长公共子序列(可能有多个),然后再一一与第三个字符串比较,找出三者的最长公共子序列。然后就GG了。想不通,思路应该是对的啊。所以又留了一道题来想。

  然后三维的状态转移很好写。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<map>
 6 #define maxn 125
 7 using namespace std;
 8 char a[maxn],b[maxn],c[maxn];
 9 int n,f[maxn][maxn][maxn];
10 int main()
11 {
12     freopen("subq.in","r",stdin);
13     freopen("subq.out","w",stdout);
14     cin>>n;
15     scanf("%s%s%s",a+1,b+1,c+1);
16     for (int i=1;i<=n;i++)
17       for (int j=1;j<=n;j++)
18         for (int k=1;k<=n;k++)
19         {
20             f[i][j][k]=max(f[i-1][j][k],max(f[i][j-1][k],f[i][j][k-1]));
21             if (a[i]==b[j]&&b[j]==c[k])
22               f[i][j][k]=f[i-1][j-1][k-1]+1;
23         }
24     cout<<f[n][n][n];
25     return 0;
26 }

不要后悔。。。


第二题:

  定义两个素数是连续的当且仅当这两个素数之间不存在其他的素数(如 7,11 ,(23,29)。给定N,K,在不超过N的正整数中求能够分解为K个连续的素数的和的最大的那个是多少。

解:

  先开始连题都读错了,想着完了我肯定不会,这是唯一分解定理啊,数论没看过啊。然后再定睛几看,额,只是一个和而已好吗。下次要先把题读清楚。

  然后就是先求出10^6以内的素数,然后 前缀和+二分答案。哦,因为一个二分模板的问题,哎。贴一个二分模板:

int l=1 , r=n+1;
    while(l<r) // the minimum line above P(x0,y0)
    {
        int m = (l+r)>>1;
        if(check(m)) r = m;//在下面;
        else l = m + 1;
    }
    return l-1;

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 1000005
 6 #define ll long long
 7 using namespace std;
 8 int t,n[2005],k[2005],ma,su[maxn],idx;
 9 ll he[maxn];
10 bool zhi[maxn];
11 void get_zhi(int x)
12 {
13     memset(zhi,true,sizeof(zhi));
14     for (int i=2;i*i<=x;i++)
15     if (zhi[i]){
16         for(int j=i*i;j<=x;j+=i)
17         if (zhi[j]){
18             zhi[j]=false;
19         }
20     }
21     zhi[1]=false;
22     for (int i=2;i<=x;i++)
23     if (zhi[i]) {
24         //su[++idx]=i;
25         ++idx;
26         he[idx]=(ll)he[idx-1]+i;
27     }
28 }
29 void work(int x,int y)
30 {
31     int l=y,r=idx;//l
32     ll ans=-1;
33     while (l<=r){
34         int mid=(l+r)>>1;
35         ll an=he[mid]-he[max(0,mid-y)];
36         if (an<=x){l=mid+1;ans=an;}
37         else r=mid-1;
38     }
39     printf("%I64d
",ans);
40     /*if (he[l]-he[l-y]>x) {
41         l--;ans=he[l]-he[l-y];
42     }
43     //if (l+1>y&&he[l]-he[l-y]>x) 
44     else if (ans!=-1&&he[l]-he[l-y]>x&&l-1<=y) ans=-1;
45     if (l-y<0) ans=-1;*/
46     //l+=1;
47     /*for (int i=l;i>=y;i--)//****
48     {
49         if (i>idx) continue;
50         if (he[i]-he[i-y]<=1) {//****
51             printf("-1
");
52             return ;
53         }
54         else if (he[i]-he[i-y]<=x) {
55             printf("%I64d
",he[i]-he[i-y]);
56             return ;
57         }
58     } 
59     printf("-1
");*/
60 }
61 int main()
62 {
63     freopen("dun.in","r",stdin);
64     freopen("dun.out","w",stdout);
65     cin>>t;
66     for (int i=1;i<=t;i++)
67     {
68         scanf("%d%d",&n[i],&k[i]);
69         if (n[i]>ma) ma=n[i];
70     }    
71     get_zhi(ma);
72     for (int i=1;i<=t;i++)
73         work(n[i],k[i]);
74     return 0;
75 }

第三题

  有一个村庄在闹饥荒,善良而土豪的YGH决定给他们发放救济粮,该村庄有 n 户人家,每两户人家之间只有一条路可以互相到达,即这些人家之间形成一棵树。现在 YGH 会以这样的形式给他们发放粮食,选择两户人家,然后对这两个户人家路径上的所有人家都发放一袋种类为 w 的救济粮。在完成一系列发放任务后,YGH 想知道每一户人家收到的粮食中数量最多的是哪一种。

解:

  40%:暴力。注意dfs的返回如果没有加判断,那么idx一直往下减就会下标超界。。然后就不知道哪里的值会被改了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 1005
 6 using namespace std;
 7 int n,q,road[maxn],idx;
 8 int tot,he[maxn],ne[maxn*2],to[maxn*2];
 9 bool vis[maxn],can=false;
10 struct pp{
11     int sum;
12     int w[maxn],num[maxn];
13 };
14 pp house[maxn];
15 void add(int a,int b)
16 {
17     tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
18 }
19 void update(int x,int y,int ad)
20 {
21     road[++idx]=x;
22     vis[x]=true;
23     if (x==y){
24         while (idx)
25         {
26             int s=road[idx];
27             bool yes=false;
28             for (int i=1;i<=house[s].sum;i++)
29               if (house[s].w[i]==ad){
30                   house[s].num[i]++;
31                   yes=true;
32                   break;
33               }
34             if(!yes){
35                 house[s].sum++;
36                 house[s].w[house[s].sum]=ad;
37                 house[s].num[house[s].sum]++;
38             }
39             idx--;
40         }
41         can=true;
42         return ;
43     }
44     for (int i=he[x];i;i=ne[i])
45     if (!vis[to[i]]){
46         vis[to[i]]=true;
47         update(to[i],y,ad);
48         if (can) return ;//回溯不加判断会下标超界 
49         vis[to[i]]=false;
50         idx--;
51     }
52 }
53 int main()
54 {
55     freopen("rice.in","r",stdin);
56     freopen("rice.out","w",stdout);
57     cin>>n>>q;
58     for (int i=1;i<n;i++)
59     {
60         int x,y;
61         scanf("%d%d",&x,&y);
62         add(x,y);
63         add(y,x);
64     }
65      for (int i=1;i<=q;i++)
66     {
67         int x,y,z;idx=0;can=false;
68         memset(road,0,sizeof(road));
69         memset(vis,0,sizeof(vis));
70         scanf("%d%d%d",&x,&y,&z);
71         update(x,y,z);
72     }
73     for (int i=1;i<=n;i++)
74     {
75         int mx=0,cur=12345678;
76         for (int j=1;j<=house[i].sum;j++)
77         {
78             if (house[i].num[j]>mx) 
79                 mx=house[i].num[j];
80         }
81         for (int j=1;j<=house[i].sum;j++)
82         if (house[i].num[j]==mx) {
83             if (house[i].w[j]<cur) cur=house[i].w[j];
84         }
85         if (cur==12345678) cout<<"0"<<endl;
86         else printf("%d
",cur);
87     }
88     return 0;
89 }
90 //30 min

  100%:树剖。先挖坑。

原文地址:https://www.cnblogs.com/lx0319/p/6052361.html