noip2018自测报告
昨天和今天测了一下前年noip tg的题
100+80+20+60+45+0=305pts
应该是大众分了。。刚好压前年我省1=线。。
我还是太弱了/kk
提交的代码:
D1T1:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=2e5; int n,a[N],ans; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) if(a[i]-a[i-1]>0)ans+=a[i]-a[i-1]; printf("%d",ans); return 0; }
D1T2:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=105; const int M=3e6+10; int T,n,a[N],dp[M],ans,sum; void clear(){ memset(dp,0,sizeof(dp)); dp[0]=1;ans=n; } int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n);clear(); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum+=a[i]; } sort(a+1,a+n+1); for(int i=1;i<=n;i++){ if(dp[a[i]]){ans--;continue;} for(int j=a[i];j<=sum;j++) dp[j]|=dp[j-a[i]]; } printf("%d\n",ans); } return 0; }
D1T3:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=5e5+10; int n,m,tot=0,vis[N],ans,id; int to[N],val[N],pre[N],now[N]; void add(int x,int y,int z){ pre[++tot]=now[x]; to[tot]=y,val[tot]=z; now[x]=tot; } void dfs(int x,int fk){ vis[x]=true; if(fk>=ans){id=x;ans=fk;} for(int i=now[x];i;i=pre[i]){ int y=to[i]; if(vis[y])continue; dfs(y,fk+val[i]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1,u,v,l;i<n;i++){ scanf("%d%d%d",&u,&v,&l); add(u,v,l);add(v,u,l); } dfs(1,0); memset(vis,0,sizeof(vis));ans=0; dfs(id,0); printf("%d",ans); return 0; }
T1:
看到T1后我们可以画个图:
我们把深度看成高度,分成了$max { a[i] } $层
很显然答案就是每一层被分开的区间数的总和
Subcode:
for(int h=1;h<=MaxA;h++) for(int i=1;i<=n;i++) if(a[i]>=h&&a[i-1]<=h)ans++;
时间复杂度为$O(n$\times$max{a[i]})$;
我们再看一下
其实每一次的答案的累加只与相邻的两项有关
而且对答案的贡献就是$a[i] - a[i-1] (a[i] > a[i-1] )$
时间复杂度$O(n)$;
T2:
猜结论的
已经能被其他钱币凑出来的就不用了
这有dalao的数学证明:
https://www.luogu.com.cn/blog/lymoe/solution-p5020
T了20分,交的时候没把sum换成mx,因为答案只关心值域以内的
T3:
有很好拿的55分的暴力
(1).求树上距离最长的两个点(其实就是树的直径)
(2).一条链
(3).菊花图
我只拿了(1)的暴力20
先求出距离1最远的点,然后以那个点作为起点,再找一个最远的点
(2)一段区间的二分答案,但是我是懒鬼就没打了。。
(3)把边权排序,计算再比较就行了
正解是二分答案+我看不懂的操作
我是大椈偌,不会。
-------------------------------------------------------------------------------------------------------------------------
D2T1:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=5e3+10; vector<int>G[N]; int n,m,path[N],lst,cnt; bool vis[N]; void dfs(int x){ vis[x]=true;path[++cnt]=x; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(vis[y])continue; dfs(y); } } int main(){ scanf("%d%d",&n,&m); for(int i=1,u,v;i<=m;i++){ scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end()); if(m==n-1){ dfs(1); for(int i=1;i<=cnt;i++) cout<<path[i]<<" "; return 0; } return 0; }
D2T2:
#include<bits/stdc++.h> using namespace std; const int mod=1e9+7; long long ans,n,m; int main(){ scanf("%lld%lld",&n,&m); if(n==2&&m==2)ans=12; if(n==3&&m==3)ans=112; if(n==5&&m==5)ans=7136; if(n==2&&m==3)ans=36; if(n==3&&m==2)ans=36; if(n==2){ ans=4; for(int i=2;i<=m;i++) ans=ans*3%mod; } printf("%lld",ans); return 0; }
D2T3:没写(看到题面长就。。。了)
T1:
n=m-1,且所有点能互相到达。
前50分很明显是个树
要使字典序最小,只需要将边权排序,然后dfs就van了
n==m就是基环树
我太菜了,不会。。
T2:
1~4的数据直接算就行了
下面是我对n=2的分析
当n=2时 其实只有两个路径
一直R的那一条字典序大于一直D的那个
同样颜色是两条路线同时到达的,此时要使s(1)>=s(2)
在同一位上有三种情况:
(1,0)(1,1)(0,0)
所以每一对颜色对答案的贡献是3
起点和终点取0,1任意一值都行
所以答案就等于$4*3^{(m-1)}$
鉴于m比较小,就不需要快速幂了
正解其实就是对这种思路的升级版
T3:
题面还没看。。
留个坑等期中考完再弄吧
总结
1.人还是太懒了,有些暴力分觉得会写或者不想写就没打了。。
2.在家里写的,氛围和环境可能要轻松舒适些,到考场可能就没这么多分了
还是有很多东西不会,思维能力也不是很强
以后会争取敢上来的