这套题我考得不错
JZOJ NO.1 香烟
简单的纯模拟。
#include <cstdio>
using namespace std;
int n,m,ans;
int main(){
scanf("%d%d",&n,&m); ans=n;//首先答案为香烟数
while (n/m){//如果可以换香烟蒂头
ans+=n/m;//增加的香烟数
n=n/m+n%m;//现有的香烟数
}
printf("%d",ans);
return 0;
}
可是这并不是最好的AC代码。
#include <cstdio>
using namespace std;
int n,m;
int main(){
scanf("%d%d",&n,&m);
printf("%d",(n-1)/(m-1)+n);
return 0;
}
首先原来的香烟数不解释,一个烟= k k k个烟蒂,等于花费 k − 1 k-1 k−1个烟蒂,但因为不许和别人借烟,最后一个烟蒂不能用。
JZOJ NO.2 背包问题
分析
用前缀和存起它们的和,再用分组背包。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
int v,m,n[101],a[11][101]; bool f[11][5001];
int main(){
scanf("%d%d",&v,&m);
for (int i=1;i<=m;i++){
scanf("%d",&n[i]);
for (int j=1;j<=n[i];j++)
scanf("%d",&a[i][j]),a[i][j]+=a[i][j-1];//前缀和
} f[0][0]=1;
for (int i=1;i<=m;i++)
for (int p=0;p<=v;p++)
if (f[i-1][p]){ //如果前一组可以用
f[i][p]=1;//那么该组也可以用
for (int j=1;j<=n[i];j++)
for (int k=j;k<=n[i];k++)
if ((p+a[i][k]-a[i][j-1])<=v)
f[i][p+a[i][k]-a[i][j-1]]=1;//并附加该组的数据
} int i;
for (i=v;i>=1;i--) if (f[m][i]) break;//可以放
printf("%d",v-i);
return 0;
}
JZOJ NO.3 破碎的路径
#include <iostream>
#include <algorithm>
using namespace std;
struct z{string x,y;}a[12001];
bool cmp(z u,z v){return u.y<v.y;}
int n,next[12001]; bool f[12001];
int main(){
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++){
int l=1,r=n,mid;
while (l<=r){
mid=(l+r)>>1;
if (a[mid].y>a[i].x) r=mid-1;
else if (a[mid].y<a[i].x) l=mid+1;
else break;
}
if (a[mid].y==a[i].x) next[mid]=i,f[i]=1;//查得到就赋值
} int i;
for (i=1;i<=n;i++) if (!f[i]) break;//没有标记说明从这个地方开始走
for (int j=i;j;j=next[j]) cout<<a[j].x<<" "<<a[j].y<<endl;
return 0;
}
JZOJ NO.4 无线网络
分析
其实一开始我是想用prim做的,听正解时惊呼:原来是并查集
代码
#include <cstdio>
#include <cmath>
using namespace std;
int n,d,u,v,f[1002],x[1002],y[1002]; bool use[1002]; int a[1002][1002];
int o(int q){return q*q;} char c;
int getf(int u){if (f[u]==u) return u; else return f[u]=getf(f[u]);}
int gett(int u,int k){if (f[u]==u) {f[u]=k;return k;} else return f[u]=gett(f[u],k);}
int main(){
scanf("%d%d",&n,&d);
for (int i=1;i<=n;i++){
scanf("%d%d",&x[i],&y[i]);f[i]=i;
for (int j=1;j<i;j++) if (d>=sqrt((double)o(x[i]-x[j])+o(y[i]-y[j]))) //符合距离
a[i][++a[i][0]]=j,a[j][++a[j][0]]=i;//邻接表
}
while (scanf("\n%c %d",&c,&u)==2){
if (c=='O'){
use[u]=1;//可以使用
for (int i=1;i<=a[u][0];i++)
if (use[a[u][i]]&&f[u]==u) f[u]=getf(a[u][i]);//合并祖先
else if (use[a[u][i]]) f[a[u][i]]=gett(a[u][i],f[u]);//合并祖先
}
else{
scanf("%d",&v);
if (!(use[u]&&use[v])) puts("FAIL");//没有修复好
else {
int fa=getf(u),fb=getf(v);
if (fa==fb) puts("SUCCESS");//祖先相同
else puts("FAIL");
}
}
}
return 0;
}