NOIP提高组历年真题题解
2018
铺设道路
差分水题,推一下结论就好了。
#include<cstdio>
#include<algorithm>
using namespace std;
int a[],d[],ansz,ansf;
int main()
{
int n;
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&a[i]),d[i]=a[i]-a[i-];
for(int i=;i<=n;i++)
{
if(d[i]<) ansf-=d[i];
else ansz+=d[i];
}
printf("%d\n",max(ansz,ansf));
return ;
}
货币系统
一开始以为是数学题,后来发现可以$dp$,很有意思的完全背包简单变形。
$f$数组下标存储每一个数,$true$表示已经出现,$false$表示不能被表示。
初始化$f[0]$为$true$。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[],f[],T;
int main()
{
scanf("%d",&T);
while(T--)
{
int ans=,maxn=;
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&a[i]),maxn=max(maxn,a[i]);
sort(a+,a++n);
memset(f,,sizeof(f));
f[]=true;//f的下标代表的是这个数是否出现过
for(int i=;i<=n;i++)
{
if(f[a[i]])continue;//如果出现过 continue
ans++;//默认没出过
for(int j=a[i];j<=maxn;j++)
f[j]=max(f[j-a[i]],f[j]);//如果j-a[i]出现过,可以保证的是j也能出现,这就是一个true的赋值转移
}
printf("%d\n",ans);
}
return ;
}
赛道修建
通过这道题我对图论$dfs$过程的理解又加深了许多,其实就是从根节点一直递归到叶节点,得到结果再一层层递归回去,和普通递归无异。一晚上只做了一道题还行..
题意大概就是:给一棵树,选$m$条路径,使最小的路径值最大。
先讲暴力分。(暴力真的是打得比正解还艰难..)
$25pts$:整张图是一条链。($b[i]=a[i]+1$)
问题转化成:有$n-1$个值,需要把这些值划分成$m$个区间,求最小区间的最大值。
裸的二分。
当然要注意一点,要求出正确的链,所以要$dfs$一次。
void dfs(int u,int fa)//预处理
{
for(int i=h[u];i!=-;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);
a[u]=e[i].w;
}
}
bool check(int pos)//二分
{
int now=,cnt=;
for(int i=;i<n;i++)
{
now+=a[i];
if(now>=pos)cnt++,now=;
}
if(cnt>=m)return true;
else return false;
}
dfs(,);
while(l<=r)
{
mid=(l+r)>>;
if(check(mid))l=mid+;
else r=mid-;
}
printf("%d\n",l-);
$20pts$:菊花图
菊花图就更简单了,从大到小排个序,$a[i]+a[2*m-i+1]$求$min$就可以了。
if(u==)tot++;
bool cmp(int a,int b){return a>b;}
if(tot==n-)
{
int las=0x7f7f7f7f;
sort(s+,s+n,cmp);
for(int i=;i<=m;i++)
las=min(las,s[i]+s[*m-i+]);
printf("%d\n",las);
return ;
}
$10pts$:$m=1$
求一遍树的直径即可。
void dp(int u)
{
vis[u]=;
for(int i=h[u];i!=-;i=e[i].nxt)
{
int v=e[i].v;
if(vis[v])continue;
dp(v);
ans=max(ans,f[u]+f[v]+e[i].w);
f[u]=max(f[u],f[v]+e[i].w);
}
}
$55pts$完整代码
#include<bits/stdc++.h>
using namespace std;
int n,m,l,r,mid,a[],h[],cnt,f[],vis[],ans,s[],tot;
struct node
{
int v,w,nxt;
}e[];
void add(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=h[u];
h[u]=cnt;
}
void dfs(int u,int fa)
{
for(int i=h[u];i!=-;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);
a[u]=e[i].w;
}
}
bool check(int pos)
{
int now=,cnt=;
for(int i=;i<n;i++)
{
now+=a[i];
if(now>=pos)cnt++,now=;
}
if(cnt>=m)return true;
else return false;
}
void dp(int u)
{
vis[u]=;
for(int i=h[u];i!=-;i=e[i].nxt)
{
int v=e[i].v;
if(vis[v])continue;
dp(v);
ans=max(ans,f[u]+f[v]+e[i].w);
f[u]=max(f[u],f[v]+e[i].w);
}
}
bool cmp(int a,int b){return a>b;}
int main()
{
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
memset(h,-,sizeof(h));
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(u==)tot++;
s[i]=w;
r+=w;
add(u,v,w),add(v,u,w);
}
if(tot==n-)
{
int las=0x7f7f7f7f;
sort(s+,s+n,cmp);
for(int i=;i<=m;i++)
las=min(las,s[i]+s[*m-i+]);
printf("%d\n",las);
return ;
}
else if(m==)
{
dp();
printf("%d\n",ans);
return ;
}
dfs(,);
while(l<=r)
{
mid=(l+r)>>;
if(check(mid))l=mid+;
else r=mid-;
}
printf("%d\n",l-);
return ;
}
$100pts$
看到“最小的最大”,很自然地想到二分,二分一个答案$mid$,每一次$dfs$去累加答案$cnt$。
我们考虑,一条合法的路径要$>=mid$,从任意一个点开始,往下递归,如果遇到了$>=mid$的路径,就$cnt++$,否则就把这条路径暂时存起来,等待这条路径找到和另一条起点相同的路径/边组合在一起成为一条合法路径。
怎么说都是$Talk is cheap$,那就上代码吧,就是个树上$dp$,我用$multiset$过的。
代码中有一些奇怪的东西, 是$sukechao$学长帮我调试的时候加上的,挨骂就挨骂吧,学长$tql$!
#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,h[],cnt,ans;
multiset<int>s[];
multiset<int>::iterator it;
struct node
{
int v,w,nxt;
}e[<<];
void add(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].nxt=h[u];
e[cnt].w=w;
h[u]=cnt;
}
int tot=;
int dfs(int u,int fa,int k)
{
// cout<<++tot<<" ";
// cout<<u<<" 死龟儿cjy"<<endl;
s[u].clear();
for(int i=h[u];i!=-;i=e[i].nxt)
{
int v=e[i].v,w=e[i].w;
if(v==fa)continue;
int val=dfs(v,u,k)+w;
if(val>=k)ans++;
else s[u].insert(val);
}
int maxn=;
while(!s[u].empty())
/*本while循环是一个寻找半链的过程 从最小的s[u].begin()开始 寻找k-s[u].begin()的前驱 如果找到了就ans++
找不到的话说明s[u].begin()对于半链路径是无用的 就可以用来更新全链路径 也就是往上跳
类似于一个树上贪心的过程 能找多少路径就找多少条 让每一条路径向着k去靠 就能找到最多的路径 正确性是显而易见的
而关于是否会重复的问题
因为我们这棵树是从下到上递归的 所以过程中要么因为找到半链路从multiset中删除并且更新答案
要么成为全链子节点向下的最优解(必须要选最优解哈)
如果全链满足条件 更新答案
否则就进入set 向上跳
重复的情况是不会出现的 正确性显然
*/
{
if(s[u].size()==)return max(maxn,*s[u].begin());//无法再寻找半链 可以向上跳
it=s[u].lower_bound(k-*s[u].begin());//二分寻找另一条半链
if(it==s[u].begin()&&s[u].count(*it)/*==1*/)it++; //找到自己了qwq
if(it==s[u].end())
{
maxn=max(maxn,*s[u].begin());//反正你也找不到另一条半链了 向上jump吧
s[u].erase(*s[u].begin());//begin()的值找不到 证明所有的这个值都找不到 所以你要全部删除
}
else
{
ans++;//成功找到半链
s[u].erase(s[u].begin());
s[u].erase(it);
}
}
return maxn;//把选剩下的maxn递归回祖宗
}
bool check(int pos)
{
ans=;
dfs(,,pos);
if(ans>=m)return true;
else return false;
}
int l,r,mid,last;
int main()
{
//freopen("testdata.in","r",stdin);
memset(h,-,sizeof(h));
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
r+=w;
}
while(l<=r)
{
// cout<<250<<endl;
tot=;
mid=(l+r)>>;
if(check(mid))l=mid+;
else r=mid-;
}
printf("%d\n",l-);
return ;
}
$dfs$的过程我可以这样解释:
首先自然递归到最底层,此时$maxn$会返回一个$0$,如果此时$0+e[i].w>=val$,答案更新,否则进入以本子树根节点为下标的$multiset$。处理了所有的子节点,开始$while$循环,如果能找到任意两个$multiset$里的元素相加$>=mid$,我们就又可以更新路径啦,为了满足贪心,我们从$s[u].begin()$开始寻找,找$mid-s[u].begin()$的前驱即可,找到了就从$multiset$中删除($erase$迭代器而不是值的本身),注意判断存在性,我在这里$wa$了好几次。同时如果某个值找不到对应的前驱,我们可以直接$erase$这个值($erase$这个值会删除所有为这个值的点,参照我$STL$的相关$blog$),因为你留着也没用了。不停找半链,找到就删除两个链的迭代器,找不到就删除所有值和这条链相同的链,当然在这之前应该$max$一波,$size=1$的时候也要max,因为最后要递归回去一个值给父亲节点。这个递归回去的值一定是不能在半链查找中发挥作用的路径的最大值,因为其他没有被选为半链组合的路径不能更优了。
总结下来,我们从最底层往上跳,有$>=mid$的值直接计入答案,否则进入$multiset$,然后在这一层的$multiset$当中找到可以组合为合法路径的半链,找到就$erase$迭代器,找不到就用来更新返回值的$max$值,然后删除所有的这种值的链,然后把这个最大值(其他没有被组合为合法路径的半链不会更优)接到父亲节点上去更新全链,这样就是一个贪心的过程,且正确性显而易见。
旅行
这个题虽然很暴力,不过也很有意思,它又让我加深了自己对递归执行的理解。首先,题中有一个可爱的隐含条件“任意选定一个城市作为起点,然后从起点开始,每次可以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市。”仔细读这个条件,含义是:我们每一次可以选择向前走到一个没走过的城市,也可以选择后退回到一个走过的城市,但不能前进到走过的城市,也不能后退到没走过的城市。我开始还以为多难呢..
认真读题真的 太 重 要 了!
$60pts$(一棵树)
非常好拿,我们考虑建一个$vector$来存储这张图,从小到大排序就可以了,$30$+行代码轻轻松松水$60$分。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int n,m,h[],cnt,ans[],vis[];
vector<int>e[];
void dfs(int u)
{
ans[++cnt]=u;
vis[u]=true;
for(int i=;i<e[u].size();i++)
{
int v=e[u][i];
if(vis[v])continue;
dfs(v);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=;i<=n;i++)
sort(e[i].begin(),e[i].end());
dfs();
for(int i=;i<=cnt;i++)
printf("%d ",ans[i]);
return ;
}
$100pts$(基环树)
也很好拿,在我们遍历的这个过程中,无论我们选择怎么走,最终只会走$n-1$条道路,第$n$条道路就是多余的,你可以选择暴力删除每一条边,也可以先把这个环预处理出来删除环,删除环的方式应该算$Tarjan$找环,也算新学了点知识,找到环之后依次删除环中的每一条边,进行遍历,最后输出每一次遍历的最小字典序。
$qwq$也太暴力了...
$vis[]$数组和$fa$都能判断退出环,但是$vis[]$更保险一点点。
#include<bits/stdc++.h>
using namespace std;
int n,m,h[],cnt,ans[],temp[],fa[],dfn[],idx,loop[],tot,top,vis[];
vector<int>ve[];
void dfs(int u)
{
dfn[u]=++idx;
for(int i=;i<ve[u].size();i++)
{
int v=ve[u][i];
if(v==fa[u])continue;
if(dfn[v])
{
if(dfn[v]<dfn[u])continue;
loop[++tot]=v;
for(;v!=u;v=fa[v])
loop[++tot]=fa[v];
}
else
{
fa[v]=u;
dfs(v);
}
}
}
void violent(int u,int pre,int uu,int vv)
{
temp[++top]=u;
for(int i=;i<ve[u].size();i++)
{
int v=ve[u][i];
if(v==pre)continue;
if((u==uu&&v==vv)||(u==vv&&v==uu))continue;
violent(v,u,uu,vv);
}
}
int main()
{
memset(ans,0x3f,sizeof(ans));
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
ve[u].push_back(v);
ve[v].push_back(u);
}
for(int i=;i<=n;i++)
sort(ve[i].begin(),ve[i].end());
if(n==m)
{
dfs();
loop[++tot]=loop[];
int now=;
tot--;
while(now<=tot)
{
// memset(vis,0,sizeof(vis));
memset(temp,,sizeof(temp));
top=;
bool flag=false;
int uu=loop[now],vv=loop[++now];
violent(,,uu,vv);
for(int i=;i<=n;i++)
{
if(ans[i]==temp[i])continue;
else
{
if(ans[i]<temp[i])flag=false;
else flag=true;
break;
} }
if(flag)
{
for(int i=;i<=n;i++)
ans[i]=temp[i];
}
}
for(int i=;i<=n;i++)
printf("%d ",ans[i]);
return ;
}
violent(,,,);
for(int i=;i<=n;i++)
printf("%d ",temp[i]);
return ;
}
2017
小凯的疑惑
这道题正式转化为:巨鱼的疑惑,我没有看任何题解,第一眼就是$exgcd$,居然随便改改就过了...证明我自己都不会写,蒙了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
int a,b,x,y,ans;
int exgcd(int a,int b)
{
if(!b)
{
x=,y=;
return a;
}
ans=exgcd(b,a%b);
int temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
signed main()
{
scanf("%lld%lld",&a,&b);
exgcd(a,b);
int A=b/ans,B=a/ans;
x=(x%A+A)%A,y=(y%B+B)%B;
printf("%lld\n",a*x+b*y-a-b-);
return ;
}
2016
组合数问题
大水题,主要是我一直不知道杨辉三角的这个性质..
若用$C$表示组合数,则$C(n,m)=C(n-1,m-1)+C(n-1,m)$,这个式子也是杨辉三角的式子,通常适用于n,m比较小的情况。预处理$c[i][i]=c[i][0]=1$。
这个题取模就可以,如果$%$的结果为$0$,则代表它是满足条件的,乱搞就行,然后写一个二维前缀和,基本就解决了。
#include<cstdio>
int T,n,m,k,a[][],s[][],f[][];
int main()
{
scanf("%d%d",&T,&k);
for(int i=;i<=;i++)
a[i][i]=,a[i][]=;
for(int i=;i<=;i++)
for(int j=;j<=i;j++)
{
a[i][j]=(a[i-][j]+a[i-][j-])%k;
if(a[i][j]==)f[i][j]=;
}
for(int i=;i<=;i++)
for(int j=;j<=;j++)
s[i][j]=s[i-][j]+s[i][j-]-s[i-][j-]+f[i][j];
while(T--)
{
scanf("%d%d",&n,&m);
printf("%d\n",s[n][m]);
}
return ;
}
玩具谜题
#include<bits/stdc++.h>
using namespace std;
int n,m,cd[],tot=;
bool qz[],fx[],temp;
string s[];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
cin>>qz[i]>>s[i];
}
for(int i=;i<=m;i++)
{
scanf("%d%d",&fx[i],&cd[i]);
}
tot=;
temp=qz[tot];
for(int i=;i<=m;i++)
{
if(temp==false)
{
if(fx[i]==false)
{
tot-=cd[i];
if(tot<=) tot+=n;
temp=qz[tot];
}
else if(fx[i]==true)
{
tot+=cd[i];
if(tot>n) tot-=n;
temp=qz[tot];
}
}
else if(temp==true)
{
if(fx[i]==false)
{
tot+=cd[i];
if(tot>n) tot-=n;
temp=qz[tot];
}
else if(fx[i]==true)
{
tot-=cd[i];
if(tot<=) tot+=n;
temp=qz[tot];
}
}
}
cout<<s[tot]<<endl;
return ;
}
2015
神奇的幻方
水题。
#include<cstdio>
using namespace std;
int n;
struct node{int x,y;}a[];
int vis[][];
int main()
{
scanf("%d",&n);
a[].x=,a[].y=(n+)>>;
vis[][(n+)>>]=;
int cnt=;
while(cnt<=n*n)
{
if(a[cnt-].x==&&a[cnt-].y!=n)a[cnt].x=n,a[cnt].y=a[cnt-].y+,vis[a[cnt].x][a[cnt].y]=cnt;
if(a[cnt-].x!=&&a[cnt-].y==n)a[cnt].x=a[cnt-].x-,a[cnt].y=,vis[a[cnt].x][a[cnt].y]=cnt;
if(a[cnt-].x==&&a[cnt-].y==n)a[cnt].x=a[cnt-].x+,a[cnt].y=a[cnt-].y,vis[a[cnt].x][a[cnt].y]=cnt;
if(a[cnt-].x!=&&a[cnt-].y!=n)
{
if(vis[a[cnt-].x-][a[cnt-].y+])a[cnt].x=a[cnt-].x+,a[cnt].y=a[cnt-].y,vis[a[cnt].x][a[cnt].y]=cnt;
else a[cnt].x=a[cnt-].x-,a[cnt].y=a[cnt-].y+,vis[a[cnt].x][a[cnt].y]=cnt;
}
cnt++;
}
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
printf("%d ",vis[i][j]);
printf("\n");
}
return ;
}
跳石头
二分答案。
#include<bits/stdc++.h>
using namespace std;
const int N=;
int a[N],d,n,m;
inline int read(){//我喜欢快读
int num = ;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else
num = c - '';
while (isdigit(c = getchar()))
num = num * + c - '';
return (flag ? - : ) * num;
}
int check(int x)
{
int prev=,next=;
int tot=;
while(next<n+)
{
next++;
if(a[next]-a[prev]<x) ++tot;
else prev=next;
}
return tot;
}
int main()
{
d=read();
n=read();
m=read();
for(int i=;i<=n;i++)
{
a[i]=read();
}
a[]=;
a[n+]=d;
int l=,r=d;
// int ans=0;
while(l<r)
{
int mid=(l+r+)>>;
if(check(mid)<=m) l=mid;
else r=mid-;
}
printf("%d\n",l);
return ;
}
2014
生活大爆炸版石头剪刀布
#include<bits/stdc++.h>
using namespace std;
int a,b,n,sa,sb,aa[],bb[],k,i=,j=;
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int w=;w<=a;w++)
{
scanf("%d",&k);
aa[w]=k;
}
for(int w=;w<=b;w++)
{
scanf("%d",&k);
bb[w]=k;
}
for(int w=;w<=n;w++)
{
i++;
j++;
if(i==a+) i=;
if(j==b+) j=;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sa++;
if(aa[i]==&&bb[j]==)sb++;
if(aa[i]==&&bb[j]==)sb++;
}
printf("%d %d\n",sa,sb);
return ;
}
2013
货车运输
题意很明晰,$Kruskal$求最小生成树+树上倍增求区间最大值。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int tot;
//#pragma GCC optimize(3)
//#pragma -fcrossjumping
//#pragma -fdefer-pop
//#pragma -fmerge-constans
//#pragma -fthread-jumps
//#pragma -floop-optimize
//#pragma -fif-conversion
//#pragma -fif-conversion2
//#pragma -fdelayed-branch
//#pragma -fguess-branch-probability
//#pragma -fcprop-registers
//#pragma -fforce-mem
//#pragma -foptimize-sibling-calls
//#pragma -fstrength-reduce
//#pragma -fgcse
//#pragma -fcse-follow-jumps
//#pragma -frerun-cse-after-loop
//#pragma -fdelete-null-pointer-checks
//#pragma -fextensive-optimizations
//#pragma -fregmove
//#pragma -fschedule-insns
//#pragma -fsched-interblock
//#pragma -fcaller-saves
//#pragma -fpeephole2
//#pragma -freorder-blocks
//#pragma -fstrict-aliasing
//#pragma -funit-at-a-time
//#pragma -falign-functions
//#pragma -fcrossjumping
//#pragma -finline-functions
//#pragma -fweb
int n,m,Q;
struct Kruskal
{
int u,v,w;
}k[];
struct node
{
int v,nxt,w;
}e[];
int h[],fa[],cnt,p[][],w[][],d[],vis[];
bool cmp(Kruskal a,Kruskal b){return a.w>b.w;}
int find(int x){return fa[x]==x?x:find(fa[x]);}
int min(int x,int y)
{
if(x>y)return y;
else return x;
}
void add(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=h[u];
h[u]=cnt;
}
void kruskal()
{
for(int i=;i<=m;i++)
{
int x=find(k[i].u);
int y=find(k[i].v);
if(x==y)continue;
tot++; fa[x]=y;
add(k[i].u,k[i].v,k[i].w);
add(k[i].v,k[i].u,k[i].w);
if(tot==n)break;
}
}
void dfs(int u,int fa)
{
vis[u]=;
d[u]=d[fa]+;
p[u][]=fa;
for(int i=h[u];i!=-;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa)continue;
w[v][]=e[i].w;
p[v][]=u;
dfs(v,u);
}
}
int lca(int a,int b)
{
int ans=0x7f7f7f7f;
if(d[a]>d[b])swap(a,b);
for(int i=;i>=;i--)
if(d[a]<=(d[b]-(<<i)))ans = min(ans,w[b][i]),b=p[b][i];
if(a==b)return ans;
for(int i=;i>=;i--)
{
if(p[a][i]==p[b][i])continue;
ans = min(ans,min(w[a][i],w[b][i]));
a=p[a][i],b=p[b][i];
}
return min(ans,min(w[a][],w[b][]));
}
inline void read(int&x)
{
x=;char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')x=x*+c-'',c=getchar();
}
inline void print(int x)
{
if(x<){putchar('-');x=-x;}
if(x>) print(x/);
putchar(x%+''); }
int main()
{
memset(w,0x7f7f7f7f,sizeof(w));
memset(h,-,sizeof(h));
read(n),read(m);
for(int i=;i<=m;i++)
read(k[i].u),read(k[i].v),read(k[i].w);
sort(k+,k++m,cmp);
for(int i=;i<=n;i++)fa[i]=i;
kruskal();
for(int i=;i<=n;i++)
if(!vis[i])dfs(i,i);
for(int j=;(<<j)<=n;j++)
for(int i=;i<=n;i++)
if(p[i][j-])p[i][j]=p[p[i][j-]][j-],w[i][j]=min(w[i][j-],w[p[i][j-]][j-]);
read(Q);
while(Q--)
{
int x,y;
read(x),read(y);
if(find(x)!=find(y))print(-),printf("\n");
else print(lca(x,y)),printf("\n");
}
return ;
}
2012
同余方程
#include<cstdio>
using namespace std;
int x,y,a,b;
int exgcd(int a,int b)
{
if(b==)
{
x=,y=;
return a;
}
int ans=exgcd(b,a%b);
int temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
int main()
{
scanf("%d%d",&a,&b);
int gcdx=(b/exgcd(a,b));
int gcdy=(a/exgcd(a,b));
x=(x%gcdx+gcdx)%gcdx;
y=(y%gcdy+gcdy)%gcdy;
printf("%d\n",x);
return ;
}
2011
铺地毯
#include<bits/stdc++.h>
using namespace std;
int xa[],xi[],ya[],yi[],x,y,a,b,c,d,flag=,n;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
xi[i]=a;
xa[i]=a+c;
yi[i]=b;
ya[i]=b+d;
}
scanf("%d%d",&x,&y);
for(int i=;i<=n;i++)
{
if(xi[i]<=x&&xa[i]>=x&&yi[i]<=y&&ya[i]>=y)
flag=i;
}
if(flag)
{
printf("%d\n",flag);
return ;
}
else printf("-1");
return ;
}
聪明的质监员
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+;
long long n,m,w[N],v[N],l[N],r[N],sv[N],snum[N],S,maxn=-,minn=0x7ffffff,Y,sum,ans;
bool check(int W)
{
memset(snum,,sizeof(snum));
memset(sv,,sizeof(sv));
Y=;
sum=;
for(int i=;i<=n;i++)
{
if(w[i]>=W) snum[i]=snum[i-]+,sv[i]=sv[i-]+v[i];
else snum[i]=snum[i-],sv[i]=sv[i-];
}
for(int i=;i<=m;i++)
Y+=((snum[r[i]]-snum[l[i]-])*(sv[r[i]]-sv[l[i]-]));
sum=llabs(Y-S);
if(Y>S) return true;
else return false; }
int main()
{
scanf("%lld%lld%lld",&n,&m,&S);
for(int i=;i<=n;i++)
{
scanf("%lld%lld",&w[i],&v[i]);
maxn=max(maxn,w[i]);
minn=min(minn,w[i]);
}
for(int i=;i<=m;i++)
scanf("%lld%lld",&l[i],&r[i]);
long long end=maxn+,beg=minn-;
ans=0x3f3f3f3f3f3f3f3f;
while(beg<=end)
{
long long mid=(beg+end)>>;
if(check(mid)) beg=mid+;
else end=mid-;
ans=min(ans,sum);
}
ans=min(ans,sum);
printf("%lld\n",ans);
return ;
}
2010
机器翻译
#include<bits/stdc++.h>
using namespace std;
int n,m,flag[],num[],sum,tot=,dic[];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d",&num[i]);
}
memset(flag,,sizeof(flag));
for(int i=;i<=m;i++)
{
if(flag[num[i]]==)
{
if(tot<n)
{
tot++;
dic[tot]=num[i];
flag[num[i]]=;
sum++;
}
else
{
dic[tot+]=num[i];
sum++;
flag[dic[]]=;
flag[num[i]]=;
for(int i=;i<=n;i++)
{
dic[i]=dic[i+];
}
}
}
}
printf("%d\n",sum);
return ;
}
2005
谁拿了最多奖学金
#include<bits/stdc++.h>
using namespace std;
int main()
{int n;
cin>>n;
int q[],b[],l[],m[]={},sum=,max=;
string j[n],zn=" ";
char y1[],y2[];
for(int i=;i<n;i++)
{cin>>j[i]>>q[i]>>b[i]>>y1[i]>>y2[i]>>l[i];}
for(int i=;i<n;i++)
{if(q[i]>&&l[i]>=)m[i]+=;
if(q[i]>&&b[i]>)m[i]+=;
if(q[i]>)m[i]+=;
if(q[i]>&&(y2[i]=='Y'))m[i]+=;
if(b[i]>&&(y1[i]=='Y'))m[i]+=;
if(m[i]>max){max=m[i];zn=j[i];}
sum+=m[i];
}
cout<<zn<<endl<<max<<endl<<sum<<endl;
return ;
}
2004
津津的储蓄计划
#include<stdio.h>
int main()
{
int i,month,left=,save=,sum,plan,flag=;
for(month=;month<=;month++)
{ left+=;
scanf("%d",&plan);
left = left - plan;
if(left<)
{ flag=;
break;
}
else
{i = left/;
save += (*i);
left -= (*i);
}
}
if(flag)
printf("-%d",month);
else
{ sum=((1.2*save) + left);
printf("%d",sum);
}
return ;
}
2002
均分纸牌
#include<bits/stdc++.h>
using namespace std;
int l,r,n,a[],ave,sum,step;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
ave=sum/n;
for(int i=;i<=n;i++)
a[i]-=ave;
l=;r=n;
while(a[l]==&&l<n) l++;
while(a[r]==&&r>) r--;
while(l<r)
{
a[l+]+=a[l];
a[l]=;
step++;
l++;
while(a[l]==&&l<r) l++;
}
printf("%d\n",step);
return ;
}
1998
拼数
#include<iostream>
#include<string>
#include <algorithm>
using namespace std;
int jc(int a) //排列数公式。
{
int i,m=;
for(i=;i<=a;i++)
m*=i;
return m;
}
int main()
{
int n;
string m,k,a[];
k='';
cin>>n;
int i;
for(i=;i<n;i++)
cin>>a[i];
for(i=;i<jc(n);i++) //所有排法。
{
m=a[];
for(int q=;q<n;q++)
m=m+a[q];
if(m>k)
k=m;
next_permutation(a,a+n);
}
cout<<k;
return ;
}
NOIP提高组历年真题题解的更多相关文章
- NOIP提高组2004 合并果子题解
NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...
- NOIP 2008提高组第三题题解by rLq
啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...
- $NOIp$提高组历年题目复习
写在前面 一个简略的\(NOIp\)题高组历年题目复习记录.大部分都有单独写题解,但懒得放\(link\)了\(QwQ\).对于想的时候兜了圈子的题打上\(*\). \(NOIp2018\ [4/6] ...
- CSP-J2019 NOIP普及组初赛真题(选择题部分)
NOIP初赛考试提纲 时间:10月的第2/3个星期六下午14:30~16:30 分数及形式:满分100分,形式为笔试(今年可能上机) 1.单项选择题,共15题,每题2分,共30分 2.阅读程序题,共3 ...
- noip2014提高组day2二题题解-rLq
(又是昨天的作业……本题写于昨天) (这破题都做这么久,我是不是吃枣药丸……) (好吧这是一道图论题呢) 本题地址:http://www.luogu.org/problem/show?pid=2296 ...
- CSP-J2019 NOIP普及组初赛真题(阅读程序部分)
阅读程序(程序输入不超过数组或字符串定义的范围:判断题正确填√,错误填×:除特殊说明外,判断题1.5分,选择题3分,共计40分) #include <cstdio> #include &l ...
- 最优贸易 NOIP 2009 提高组 第三题
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...
- NOIP2008提高组(前三题) -SilverN
此处为前三题,第四题将单独发布 火柴棒等式 题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0 ...
- [NOIP提高组2018]货币系统
[TOC] 题目名称:货币系统 来源:2018年NOIP提高组 链接 博客链接 CSDN 洛谷博客 洛谷题解 题目链接 LibreOJ(2951) 洛谷(P5020) 大视野在线评测(1425) 题目 ...
随机推荐
- Nacos笔记01——使用Nacos作为SpringCloud项目的服务注册中心
前言 刚学SpringCloud时使用eureka作为服务注册中心,随着网飞公司eureka2.x不再更新,以及最近在公司实习接触到的SpringCloud项目是使用Nacos来做服务注册中心的,所以 ...
- js入门之内置数组对象 Array
一. 数组 1. 创建数组的两种方式 1. 数组字面量 var array = [] 2. 数组的构造函数创建数组 var array = new Array(); 2. 如何判断一个变量是否是数组 ...
- vue -- 数组过滤 filter (vue 表格)
如下图: 左边表格滑动滚轮,可以自动赋值右边表格: 现在是后台只有一个接口,把整个页面的数据全部返回出来了, 左边表格滑动到每一项时显示右边表格内容,但是需要code相同: 问题: 右边表格 ...
- Django之form表单详解
构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的模板: <form action="/your-name/" method=" ...
- Java8新特性之重复注解(repeating annotations)
一.什么是重复注解 允许在同一申明类型(类,属性,或方法)的多次使用同一个注解 二.一个简单的例子java 8之前也有重复使用注解的解决方案,但可读性不是很好,比如下面的代码: 复制代码代码如下: p ...
- sql网址
w3school版 https://www.w3school.com.cn/sql/index.asp 菜鸟教程版 https://www.runoob.com/sql/sql-tutorial.ht ...
- 用Xcode配置完美ACMer环境
用Xcode配置完美ACMer环境 前言 作为\(ACMer\),需求大致为强大的文本编辑功能\((VIM)\),便捷的文件模版功能以及多文件编译功能.\(vscode\)虽然强大,但是与集成\( ...
- finally关键字执行的底层原理
1.举例子: 在主方法中调用m1方法,finally中 i 变量自增,但结果却是10 public static void main(String[] args) { int i = m1(); Sy ...
- Cookie、Session、Token那点事儿和前后端分离之JWT用户认证
(两篇文章转自:https://www.jianshu.com/p/bd1be47a16c1:https://www.jianshu.com/p/180a870a308a) 什么是Cookie? Co ...
- Jmeter逻辑控制之if控制器
一.背景 在实际工作中,当使用Jmeter做性能脚本或者接口脚本时,有可能会遇到需要对不同的条件做不同的操作,基于这种诉求,在Jmeter中可使用if控制器来实现 二.实际操作 逻辑控制器位置: 在线 ...