Test20200603

T1 种树(trees. cpp/1S/128M)

一道很简单的贪心

【问题描述】
一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号为 l„n。每个块的大小为一个单位尺寸并最多可种一棵树。每个居民想在门前种些树并指定了三个号码 b,e,t。这三个数表示该居民想在 b 和 e 之间最少种 t 棵树。当然,b≤e,居民必须保证在指定地区不能种多于地区被分割成块数的树,即要求 t≤e-b+1,允许居民想种树的各自区域可以交叉。出于资金短缺的原因,环保部门请你求出能够满足所有居民的要求,需要种树的最少数量。
【文件输入】
第一行为 n,表示区域的个数;第二行为 h,表示房子的数目;下面 h 行描述居民的需要:b e t(0<b≤e≤30000,r≤e-b+l)分别用一个空格分开。
【文件输出】
输出为满足所有要求的最少树的数量。
【样例输入】
9
4
1 4 2
4 6 2
8 9 2
3 5 2
【样例输出】
5
【数据规模】
30%的数据满足 0<n≤1000,0<h≤500;100%的数据满足 n≤30000,h≤5000。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=30005;
 4 inline int read()
 5 {
 6     int x=0;char c=getchar();
 7     for(;!isdigit(c);c=getchar());
 8     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
 9     return x;
10 }
11 
12 struct node
13 {
14     int l,r,w;
15 }p[N];
16 
17 int n,h,ans=0;
18 bool flag[N];
19 
20 inline bool cmp(node a,node b)
21 {
22     if(a.r!=b.r) return a.r<b.r;
23     return a.l<b.l;
24 }
25 
26 int main()
27 {
28     n=read();h=read();
29     for(int i=1;i<=h;i++)
30     {
31         p[i].l=read();p[i].r=read();p[i].w=read();
32     }
33     sort(p+1,p+h+1,cmp);
34     for(int i=1;i<=h;i++)
35     {
36         int sum=0;bool ok=false;
37         for(int j=p[i].l;j<=p[i].r;j++)
38         {
39             if(!flag[j]) continue;
40             sum++;
41             if(sum>=p[i].w)
42             {
43                  ok=true;
44                 break;    
45             }    
46         }
47         if(ok) continue;
48         int res=p[i].w-sum;
49         for(int j=p[i].r;res&&j>=p[i].l;j--)
50         {
51             if(!flag[j])
52             {
53                 flag[j]=true;
54                 ans++;
55                 res--;
56             }
57         }
58     }
59     printf("%d\n",ans);
60     return 0;
61 }

 

 

一道简单的树上搜索,LCA也可做
【问题描述】
在美丽的东辰(很明显是出题人改了学校名)中学里面,有一座高一学堂。所谓山不在高,有仙则名;水不在深,有龙则灵。高一学堂,因为有了 llj,就成了现在这个样子 = =。由于 llj 的语言太过雷人,每次他发微往往都会有一石激起千层浪的效果,具体就是所有关注他的人都会转发,同时@他,接着关注这些人的人也会转发,同时@他关注的人(注意转发内容本身会有@llj),以此类推。这样导致每次 llj 发微博都会被@上兆次,而 llj 又特别喜欢发,sina 支持不了如此庞大的数据量,特出规定,每次转发时,@的人不能超过 K 人,好友在转发时如果超过了,就把最早那人删掉。现在 llj 刚发了一条微博“求满分”,他想知道每个与他有联系的人分别会被@多少次。
【输入】
输入第一行有三个整数,N,K,表示人数和 K。
接下来 N-1 行,每行有 2 个整数 a,b,表示 a 和 b 有关注关系。
输入给出一棵以 1 号点为根的树,一号点代表 llj,对于任意一个点,他的儿子都关注他。
【输出】
输出有 N 行,每行有一个整数,这个人会被@多少次。
【输入样例】
5 2
1 2
2 3
2 4
4 5
【输出样例】
3
3
0
1
0
【数据规模】
对于 30%的数据,N≤100;
对于 60%的数据,N≤2000,k≤100;
对于 100%的数据,N≤100000。
 
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int x=0;char c=getchar();
 6     for(;!isdigit(c);c=getchar());
 7     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
 8     return x;
 9 }
10 int n,k,tot=0;
11 int nex[200005],to[200005],head[100005],size[100005],zuxian[100005],fa[100005];
12 int dep[100005],ans[100005]; 
13 inline void add(int x,int y)
14 {
15     nex[++tot]=head[x];
16     head[x]=tot;
17     to[tot]=y;
18 }
19 inline bool pd(int u)
20 {
21     for(int i=head[u];i;i=nex[i])
22     {
23         if(to[i]!=fa[u]) return false;
24     }
25     return true;
26 }
27 inline void dfs1(int u,int f)
28 {
29     fa[u]=f;dep[u]=dep[f]+1;
30     size[u]=1;
31     if(pd(u)&&dep[u]>=k+1)
32     {
33         zuxian[u]=u;
34         for(int i=1;i<=k+1;i++)
35         zuxian[u]=fa[zuxian[u]];
36         int now=u;
37         while(dep[now]>=k+1)
38         {
39             zuxian[fa[now]]=fa[zuxian[u]];
40             now=fa[now];
41         }
42     }
43     for(int i=head[u];i;i=nex[i])  //计算子树大小 
44     {
45         int v=to[i];
46         if(v==f) continue;
47         dfs1(v,u);
48         size[u]+=size[v];
49     }
50     
51     ans[zuxian[u]]+=size[u];   //不合法的子树们 
52 }
53 int main()
54 {
55     freopen("at.in","r",stdin);
56     freopen("at.out","w",stdout);
57     n=read();k=read();int a,b;
58     for(int i=1;i<n;i++)
59     {
60         a=read(); b=read();
61         add(a,b);add(b,a);
62     }
63     dfs1(1,0);
64     for(int i=1;i<=n;i++)
65     {
66         printf("%d\n",size[i]-ans[i]-1);
67     }
68     return 0;
69 }
 
 
T3 高二学堂 (poker.cpp/1S/256M)
这道题用来练习抢分技巧是非常可的,正解是矩阵快速幂优化的DP
【问题描述】
在美丽的东辰中学里,有座高二学堂,同样也是因为一个人,让它们变成了现在这个样子~那就是我们伟大的级主任。因为他,我们又迎来了一个木有电影,只有对答案的段考日;又迎来了一个不是大礼拜,而是小礼拜的周末。因为是小礼拜,同学们都不回家,所以干脆就回到宿舍去玩牌了。而由于三国杀太 out 了,所以现在他们都玩四国杀。四国杀(说白了就是扑克牌~)是 Wayne 发明的,源于他对升级、斗地主、锄大地等等玩法都感到厌倦了。于是他提出了这个新的玩法:Wayne 有一副加强版的扑克牌,强大到任意取一个自然数 x,在牌堆里都恰有 4 张数值为 x 的牌。每次,Wayne 随机生成两个正整数 n 和 k,然后在牌堆里
选取不超过 k 张牌,使得牌面数字之和恰为 n。已知 Wayne 玩了若干盘,每盘都算出了对应的方案数,他想请你也算出各盘方案数,以验算他的结果是否正确。
结果可能比较大,你只需要求出方案数 mod 1000000009 的值即可。
【输入】
输入文件包含不超过 10 组数据。
每行包含两个整数,表示上文中的 n 和 k。
输入数据以两个 0 表示结束。
【输出】
输出文件中,每组数据输出一行,为对应的方案数。
【输入样例 1】
2 1
2 2
2 3
50 5
0 0
【输出样例 1】
4
10
10
1823966
【数据规模】
对于 10%的数据,k=1;
对于 20%的数据,n≤10,k≤4;
对于 40%的数据,n≤1000;
对于 60%的数据,n≤100000;
对于另外 20%的数据,只有 1 组数据;
对于 100%的数据,n≤109,k≤10。

考场上只是输出4,拿10分,后来想想是可以骗很多分的

把每张牌排成一条链搜索,20分

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000009
inline int read()
{
    int x=0;char c=getchar();
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x;
}
int n,k;
int ans=0;
inline void dfs(int val,int now,int tot)
{
    if(val>n||tot>k) return;
    if(val==n)
    {
        ans=(ans+1)%mod;
        return;
    } 
    if(val+(now-1)/4+1>n) return;
    dfs(val+(now-1)/4+1,now+1,tot+1);
    dfs(val,now+1,tot);
}
int main()
{
    //freopen("poker.in","r",stdin);
    //freopen("poker.out","w",stdout);
    while(1)
    {
         n=read();k=read();    
        if(!(n+k)) break;
        ans=0;
        dfs(0,1,0);
        printf("%d\n",ans);
    }
    return 0;
}

 排成链后用01背包dp,40分

 

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000009
inline int read()
{
    int x=0;char c=getchar();
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x;
}
int n,k,ans=0;
int dp[1005][12];
int main()
{
    //freopen("poker.in","r",stdin);
    //freopen("poker.out","w",stdout);
    while(1)
    {
        n=read();k=read();    
        if(!(n+k)) break;
        if(!n||!k) printf("0\n");
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n*4;i++)
        {
            int v=(i-1)/4+1;
            for(int j=n;j>=v;j--)
                for(int q=min(i,k);q;q--)
                    dp[j][q]=(dp[j][q]+dp[j-v][q-1])%mod;
        }
        ans=0;
        for (int i=0;i<=k;i++)
             ans=(ans+dp[n][i])%mod;
        printf("%d\n",ans);   
    }
    return 0;
} 

 

 

 

 

 

posted @ 2020-06-03 20:14  SuYongkang  阅读(178)  评论(0)    收藏  举报