终于结束了。。。
JZOJ NO.1 【GDOI2005】积木分发
分析
作为最水的一道题。快排需要的积木,从小到大模拟,给不了NO,否则就YES。
代码
#include <cstdio>
#include <algorithm>
#include <cctype>
using namespace std;
struct b{int x,y;}a[10002]; int n; unsigned long long s;
bool cmp(b u,b v){return u.y<v.y;}
unsigned long long in(){
char c=getchar(); unsigned long long ans=0;
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
bool check(int s){
for (int i=1;i<=n;i++){
if (s<a[i].y) return false;//不能帮助
s+=a[i].x;//收回积木
} return true;
}
int main(){
while (n=in(),s=in(),n||s){//记住或者(二十分!)
for (int i=1;i<=n;i++) a[i].x=in(),a[i].y=in();
stable_sort(a+1,a+1+n,cmp);
if (check(s)) puts("YES"); else puts("NO");
}
return 0;
}
JZOJ NO.2 【GDOI2005】电路稳定性
分析
纯模拟,并联电路x×yx×yx×y ,串联电路x+(1−x)×yx+(1-x)×yx+(1−x)×y
代码
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;
double a[101],p[27]; char s[101]; int n;
int news(){int m=0; for (int i=1;i<=n;i++) if (a[i]) a[++m]=a[i]; a[m+1]=0; return m;}//把0都去掉
int main(){
scanf("%d\n",&n);
scanf("%s",s+1);
for (int i=1;i<=n;i++) scanf("%lf",&p[i]); n=strlen(s+1);
for (int i=1;i<=strlen(s+1);i++){
if (s[i]=='(') a[i]=-1;//(变成-1
if (s[i]==')') a[i]=-2;//以此类推
if (s[i]==',') a[i]=-3;
if (isupper(s[i]))a[i]=p[s[i]-64];//大写字母变成它对应的权值
}
while (n>1){
for (int i=1;i<=n;i++){
int j=i;
while (a[j]>0&&a[j-1]!=-3&&a[j+1]==-3&&a[j+2]>0){//串联
a[j+2]=a[j]+(1-a[j])*a[j+2];//串联公式
a[j+1]=a[j]=0,j+=2;//变成0
}
}
n=news();//清扫运算过程
for (int i=2;i<=n;i++){
int j=i;
while (a[j-1]==-1&&a[j+1]==-2&&a[j+2]==-1&&a[j+4]==-2){//并联
a[j+3]*=a[j];//并联公式
a[j-1]=a[j+1]=a[j]=0,j+=3;
}
if (a[j-1]==-1&&a[j+1]==-2&&(a[j+2]==-3||a[j+2]==-2||!a[j+2])) a[j-1]=a[j+1]=0;//删掉括号
}
n=news();//清扫运算过程
}
printf("%.4lf",a[1]);//剩下一个就是答案
return 0;
}
JZOJ NO.3 【GDOI2005】飞越原野
分析
广搜,飞行和行走
用一个循环队列存储坐标、能量、答案。
布尔数组存储是否走过,三维,下标为坐标和能量。
代码
#include <cstdio>
using namespace std;
bool v[101][101][101]; char map[101][101];
const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
struct node{
int x,y,ans,eneg;
}q[320001];
void bfs(int n,int m,int d){
int head=0,tail=0;
node f1,f2;
f1.x=f1.y=1,f1.ans=0,f1.eneg=d;//一开始初值能量满,坐标起点
q[++tail]=f1;
while (head!=tail){
f1=q[++head];//出队
head=(head-1)%(32*n*m)+1;
if (f1.x==n&&f1.y==m) {printf("%d",f1.ans);return;}//到达终点
for (int i=0;i<4;i++){//走路
f2.x=f1.x+dx[i]; f2.y=f1.y+dy[i];
if (f2.x>0&&f2.x<=n&&f2.y>0&&f2.y<=m&&!v[f2.x][f2.y][f1.eneg]&&map[f1.x][f1.y]=='P'){//可以着陆
f2.ans=f1.ans+1;//步数+1
f2.eneg=f1.eneg;//能量不变
v[f2.x][f2.y][f2.eneg]=1;//标记
q[++tail]=f2;//入队
tail=(tail-1)%(32*n*m)+1;
}
}
for (int j=2;j<=f1.eneg;j++){//飞行距离
for (int i=0;i<4;i++){
f2.x=f1.x+dx[i]*j;
f2.y=f1.y+dy[i]*j;
if (f2.x>0&&f2.x<=n&&f2.y>0&&f2.y<=m&&!v[f2.x][f2.y][f1.eneg-j]&&map[f1.x][f1.y]=='P'){//可以着陆
f2.ans=f1.ans+1;//步数+1
f2.eneg=f1.eneg-j;//减去消耗的能量
v[f2.x][f2.y][f2.eneg]=1;
q[++tail]=f2;//入队
tail=(tail-1)%(32*n*m)+1;
}
}
}
}
puts("impossible"); return;//不可能到达
}
int main(){
int n,m,d;
scanf("%d%d%d\n",&n,&m,&d);
for (int i=1;i<=n;i++) gets(map[i]+1);
bfs(n,m,d); return 0;
}
JZOJ NO.4 【GDOI2005】电子眼
分析
一开始看错题目,输出n-1,错了。&_&
原来是树形dp,如果这个路口装,那么与它相连的路口不用装,如果这个路口不装,那么与它相连的路口都要装。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int n,f[100001][2],ls[100001],a[200001];
bool v[100001];
int in(){
char c=getchar(); int ans=0;
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void dp(int x){
int s1=1,s2=0;
for (int i=ls[x-1];i<=ls[x]-1;i++){
if (!v[a[i]]){
v[a[i]]=1;//来过。
dp(a[i]);
s1+=min(f[a[i]][0],f[a[i]][1]);//装选择最小的
}
s2+=f[a[i]][1];//不装其它都要装
}
f[x][1]=s1;
f[x][0]=s2;
}
int main(){
n=in(); ls[0]=1;
for (int i=1;i<=n;i++){
int x=in(); ls[i]=ls[i-1];
for (int j=ls[i];j<=ls[i]+x-1;j++) a[j]=in();
ls[i]+=x;} //ls存储每个路口的路占用的位置
v[1]=1; dp(1);
printf("%d",min(f[1][0],f[1][1])); return 0;//装和不装的最大值
}