Test20200603
一道很简单的贪心
【问题描述】
一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号为 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; }

浙公网安备 33010602011771号