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提高组历年真题题解的更多相关文章

  1. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  2. NOIP 2008提高组第三题题解by rLq

    啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...

  3. $NOIp$提高组历年题目复习

    写在前面 一个简略的\(NOIp\)题高组历年题目复习记录.大部分都有单独写题解,但懒得放\(link\)了\(QwQ\).对于想的时候兜了圈子的题打上\(*\). \(NOIp2018\ [4/6] ...

  4. CSP-J2019 NOIP普及组初赛真题(选择题部分)

    NOIP初赛考试提纲 时间:10月的第2/3个星期六下午14:30~16:30 分数及形式:满分100分,形式为笔试(今年可能上机) 1.单项选择题,共15题,每题2分,共30分 2.阅读程序题,共3 ...

  5. noip2014提高组day2二题题解-rLq

    (又是昨天的作业……本题写于昨天) (这破题都做这么久,我是不是吃枣药丸……) (好吧这是一道图论题呢) 本题地址:http://www.luogu.org/problem/show?pid=2296 ...

  6. CSP-J2019 NOIP普及组初赛真题(阅读程序部分)

    阅读程序(程序输入不超过数组或字符串定义的范围:判断题正确填√,错误填×:除特殊说明外,判断题1.5分,选择题3分,共计40分) #include <cstdio> #include &l ...

  7. 最优贸易 NOIP 2009 提高组 第三题

    题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...

  8. NOIP2008提高组(前三题) -SilverN

    此处为前三题,第四题将单独发布 火柴棒等式 题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0 ...

  9. [NOIP提高组2018]货币系统

    [TOC] 题目名称:货币系统 来源:2018年NOIP提高组 链接 博客链接 CSDN 洛谷博客 洛谷题解 题目链接 LibreOJ(2951) 洛谷(P5020) 大视野在线评测(1425) 题目 ...

随机推荐

  1. 自定义标签之inclusion_tag

    1.在当前app下创建templatetags文件夹 2.在templatetags文件夹下面创建自定义的mytag.py文件 3.在mytag.py文件中的代码 from django.templa ...

  2. axios配置及使用(发起请求时带上token)

    1.安装 利用npm安装 npm install axios --save 2.引入即可使用 import axios from 'axios' 3.目录 4.各个文件设置: (1)env.js ex ...

  3. JS 客户端(浏览器)存储数据之 localStorage、sessionStorage和indexDB

    基本概念 1.localStorage和sessionStorage是HTML5 Web存储的提供的两种存储方式,在IE7以上以及大多数浏览器都是支持的 2.localStorage和sessionS ...

  4. javascript 箭头函数的使用 初学者必看

    为了保证可读性,本文采用意译而非直译.另外,本文版权归原作者所有,翻译仅用于学习. 本文我们介绍箭头(arrow)函数的优点. 更简洁的语法我们先来按常规语法定义函数: 1 2 3 4 5 funct ...

  5. 【Zookeeper】基础学习概览【汇总】

    一.概述 1.1 简介 1.2 Zookeeper集群机制 1.3 Zookeeper特性 二.Zookeeper应用场景 三.Zookeeper数据结构 四.Zookeeper安装 五.Java操作 ...

  6. python词云图之WordCloud

    1. 导入需要的包package import matplotlib.pyplot as plt from scipy.misc import imread from wordcloud import ...

  7. pyspider 安装

    1. sudo apt --update 2.sudo apt --upgrade 3. sudo apt-get install  ......大一推依赖包.看pyspider 官网 4.创建虚拟环 ...

  8. 2019-ACM-ICPC-南京区网络赛-D. Robots-DAG图上概率动态规划

    2019-ACM-ICPC-南京区网络赛-D. Robots-DAG图上概率动态规划 [Problem Description] ​ 有向无环图中,有个机器人从\(1\)号节点出发,每天等概率的走到下 ...

  9. bloomberg bulkfile【一】 文件的分类

    文章导航 bloomberg bulkfile [一]  文件的分类 bloomberg bulkfile [二]  文件解析 bloomberg bulkfile [三]  在oracle的存储 订 ...

  10. Git 的用法

    对于GIT  的用法,最近一直在寻找方法.网上也能找到一些方法.但是感觉说的不是很清楚,在这里我基于自己经验写一些. 对于任何一种方法都要安装GIT. 我是基于VS Code 2015 来做的. 在安 ...