【NOIP2017】SummerTraining0707
来源:互联网 发布:淘宝买家秀 编辑:程序博客网 时间:2024/06/11 05:25
这是一套大水题,8人AK,我100+0+0=100 rank29
T1乱搞题
T2树形DP,我不知道哪里搞炸了
T3更水,表示看到仙人掌就没去想了(其实是没想出)
看题解或代码的看目录,有索引。
T1
问题 A: 寻找羔羊
时间限制: 1 Sec 内存限制: 256 MB
题目描述
给定一个由小写字母组成的字符串,寻找包含“agnus”(羔羊)的子串的个数。注意:当且仅当两个子串的起始位置和终点不同时,这两个子串属于不同的子串。
输入
只有一个字符串,表示题中所述的字符串。
输出
仅一个数字,表示满足题意的子串个数。
样例输入
agnusbgnus
样例输出
6
提示
【样例解释】
6个子串分别是:agnus、agnusb、agnusbg、agnusbgn、agnusbgnu、agnusbgnus。
【数据规模和约定】
对于 40%的数据,字符串长度<=1000
对于 100%的数据,字符串长度<=30000
Solution
从头到尾遍历一次字符串,每碰到一次“agnus”,用“agnus”前面的字符数目乘上“agnus”后面的字符数目,即为含有当前“agnus”的字符串数目。
直接统计即可,不过要注意去重。
我们设找到的开头为x[i],末尾为y[i]=x[i]+4;
则个数为(x[i-1]~x[i]-1)*(y[i]+1~n),自己画一下图就行了
Code
#include <cstdio>#include <cstring>char s[30010];int i,n,ans,x;int main(){ scanf("%s",s+1); n=strlen(s+1); ans=x=0; for (i=1;i+4<=n;i++) if (s[i]=='a'&&s[i+1]=='g'&&s[i+2]=='n'&&s[i+3]=='u'&&s[i+4]=='s') {ans+=(i-x)*(n-i-3); x=i;} printf("%d\n",ans); return 0;}
T2
问题 B: 统计损失
时间限制: 1 Sec 内存限制: 512 MB
题目描述
SJY有一天被LLT紧急召去计算一些可能的损失。LLT元首管理的SHB国的交通形成了一棵树,现在将会出现一颗陨石砸在SHB国中,并且陨石砸毁的必定是SHB国构成的交通树上的一条路径。SHB国的损失可表示为被砸毁的路径上的所有城市价值之积。现在还暂时无法确定陨石的掉落路线,所以LLT元首希望SJY能够告诉他SHB国在受到每一种砸毁方式后会受到的损失之和模10086之后的值。注意:单独一个节点也被认为是合法的路径。
输入
第1行一个数n,表示城市数。
第2行n个数,第i个数表示第i个城市的价值。
第3到n+1行,每行两个数u,v,表示城市u,v之间有一条道路。
输出
包含一个数,表示SHB国将受到的损失之和。
样例输入
5
7 6 6 1 1
1 2
2 3
2 4
1 5
样例输出
778
提示
【数据规模和约定】
n<=100;
n<=3000;
n<=100000
Solution
题意即统计所有的路径权值积的和。
算法1:
DFS每个点的路径,统计答案,时间复杂度O(n^2)
算法2:
树形DP,统计每个点的子树到当前点的路径积的和,再DFS逆序计算并合并答案即可,时间复杂度O(n)。合并时需注意合并一次的效率,要保证能够做到O(子树个数)合并,并且需要注意10086不能求逆元 。
PS:这道题目我想的是LCA求路径那样的算法,结果需要求逆元……卡死
Code
#include<bits/stdc++.h>using namespace std;#define MOD 10086#define ll long longconst ll MAXN=100010;ll Head[MAXN],Next[MAXN*2],To[MAXN*2];ll a[MAXN],sum[MAXN];ll n,tot,ans;void add_eage(ll x,ll y){ tot++; Next[tot]=Head[x]; Head[x]=tot; To[tot]=y;}void dfs(ll u,ll pre){ ans+=a[u]; sum[u]=0; for (ll i=Head[u];i;i=Next[i]) { ll v=To[i]; if (v==pre) continue; dfs(v,u); ans=(ans+sum[u]*sum[v]*a[u])%MOD; sum[u]=(sum[u]+sum[v])%MOD; } ans=(ans+sum[u]*a[u])%MOD; sum[u]=(sum[u]*a[u]+a[u])%MOD;}int main(){ scanf("%lld",&n); for (ll i=1;i<=n;i++) scanf("%lld",&a[i]); for (ll i=1;i<n;i++) { ll x,y; scanf("%lld%lld",&x,&y); add_eage(x,y); add_eage(y,x); } ans=0; dfs(1,0); printf("%lld",ans); return 0;}
T3
问题 C: 简单题
时间限制: 1 Sec 内存限制: 512 MB
题目描述
dzy 手上有一张n 个点m 条边的联通无向图,仙人掌是一张每条边最多在一个简单环内的联通无向图。他想求这个无向图的生成仙人掌中最多有多少条边。
但是dzy 觉得这个问题太简单了,于是他定义了“美丽的生成仙人掌”,即在一个生成仙人掌中如果满足对于任意编号为i,j(i < j) 的两点,存在一条它们之间的简单路径上面有j-i+1 个点,则这个仙人掌是美丽的。
他现在想要知道这张图的美丽的生成仙人掌中最多有多少条边,你能帮帮他吗?
输入
第一行两个整数n,m。接下来m 行每行两个整数ui,vi,表示这两个点之间有一条无向边。保证图中没有自环。
输出
仅一行一个整数表示答案。
样例输入
2 1
1 2
样例输出
1
提示
【数据规模和约定】
对于10% 的数据,n <=10。对于30% 的数据,n <=10^3。对于100% 的数据,n <=10^5,m <= 2n。
Solution
算法1:
直接暴力枚举所有可能的边集,复杂度O(2n),期望得分10分
算法2:
研究题目可以发现,美丽的生成仙人掌中i 和i+ 1中必定有一条边。所以问题变成了:我们在一条链上加上若干条边使得得到的图是仙人掌且边数量最大。
显而易见,每一条非链边对应了链上的一个区间。于是问题就变成了选出最多数量的线段使得其互不相交。
这个可以用dp来实现,令F[i]为右端点最大为i 的区间的答案。则有:
F[i =max{F[j]+ 1(i和j之间存在一条边),f[i-1]}
时间复杂度O(n),期望得分100分,当然如果你一不小心写次了,时间复杂度O(n2),期望得分30分。
算法3:
显而易见,我们要求的是区间图的最大独立集。由于区间图把区间按右端点排序就是完美消除序列,直接贪心就可以了。时间复杂度O(nlogn)(用桶排可以做到O(n)),期望得分100分
PS:关键是用i,i+1代替i,j,我压根没想到
CODE
DP
#include<bits/stdc++.h>using namespace std;const int MAXN=100010;int Head[MAXN],Next[MAXN*2],To[MAXN*2];bool flag[MAXN]; int f[MAXN],n,m,tot;void add_eage(int x,int y){ tot++; Next[tot]=Head[x]; Head[x]=tot; To[tot]=y;}int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if (x>y) swap(x,y); if (y==x+1 && !flag[x]) { flag[x]=true;continue;} add_eage(y,x); } for (int i=1;i<=n;i++) { f[i]=f[i-1]; for (int j=Head[i];j;j=Next[j]) f[i]=max(f[i],f[To[j]]+1); } printf("%d\n",f[n]+n-1); return 0;}
贪心
#include<bits/stdc++.h>using namespace std;const int MAXN=100010;int n,m,ans,cnt,r;bool flag[MAXN];struct eage{ int x,y;}e[MAXN*2];bool cmp(eage a,eage b){ return a.y<b.y;}int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if (x>y) swap(x,y); if (y==x+1 && !flag[x]) { flag[x]=true;continue;} cnt++; e[cnt].x=x; e[cnt].y=y; } sort(e+1,e+1+cnt,cmp); ans=n-1; r=0; for (int i=1;i<=cnt;i++) if (r<=e[i].x) { ans++; r=e[i].y; } printf("%d",ans); return 0;}
- 【NOIP2017】SummerTraining0707
- noip2017
- NOIP2017
- noip2017
- NOIP2017
- NOIP2017
- NOIP2017
- NOIP2017
- NOIP2017
- 【NOIP2017】SummerTraining0720
- 【NOIP2017】SummerTraining0724
- 【NOIP2017】SummerTraining0726
- 【NOIP2017】SummerTraining0727
- 【NOIP2017】SummerTraining0721
- 【NOIP2017】SummerTraining0706
- 【NOIP2017】SummerTraining0710
- 【NOIP2017】Day1
- 【NOIP2017】Day2
- redis源码调试方法
- 喷水装置(一)
- 如何做SEO(关键词)
- ExtJS Grid获取选中值
- Codeforces-557D Vitaly and Cycle(二分图染色)
- 【NOIP2017】SummerTraining0707
- mysql中or和in的效率问题
- Introduction.to.Machine.Learning.with.Python 笔记
- PhalApi框架脱坑笔记(二:get请求的参数获取)
- app已安装检测技术原理
- C++中delete和delete[]的区别
- JS对象深度拷贝
- Android String转二维码
- MySQL索引原理及慢查询优化