1.P8509 如何得到 npy
题意:
给定一棵n个节点的树,n-1条边,和关键点,s,t,求其他所有点到s或t的最短距离和,并标记每条边的方向,为1或0或2
思路:
从s和t分别dfs1搜寻,求出每个点到s或t的最短距离,并标记是到s还是t; 从s和t分别dfs2标搜寻,求出最短距离和以及边方向
代码:
using namespace std;
#define ll long long
#define M 300005
int n,s,t,w[M],v[M];//w是到s是源点,还是t是源点,v是边是1或2或0
int idx,h[M],vet[2*M],len[M*2],nxt[M*2];
ll d[M],ans;
void add(int a ,int b ,int c){
nxt[++idx]=h[a],vet[idx]=b,len[idx]=c;
h[a]=idx;
}
void dfs1(int x,int pre,int tp){
for (int i = h[x]; i ; i=nxt[i]) {
int y=vet[i],z=len[i];
if(y==pre)continue;
if(d[y]>d[x]+z){
d[y]=d[x]+z;
w[y]=tp;
dfs1(y,x,tp);
}
}
}
void dfs2(int x,int pre,int tp){
for (int i = h[x]; i ; i=nxt[i]) {
int y=vet[i];
if(y==pre)continue;
if(w[y]==tp){
ans+=d[y];
if(i&1)
v[i/2]=1;
else
v[i/2]=2;
dfs2(y,x,tp);
}
}
}
int main(){
cin>>n>>s>>t;
idx=1;
for (int i = 1; i <=n-1 ; ++i) {
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
for (int i = 1; i <=n ; ++i) {
d[i]=1e16;
}
d[s]=0;
dfs1(s,0,s);
d[t]=0;
w[t]=0;
dfs1(t,0,t);
dfs2(s,0,s);
dfs2(t,0,t);
cout<<ans<<'\n';
for (int i = 1; i <=n-1 ; ++i) {
cout<<v[i];
}
}
2.P8508 做不完的作业
题意:
共有n个任务,一天有x时间,前i天睡觉时间不能小于rxi,r=p/q,求最少多少天可以完成任务(每天都必须睡觉)
思路:
一天时间 − 将要完成的作业时间 + 当前总睡觉时间 + l 天整天睡觉的总时长 ≥ 当前天的 l 天后的要求总睡觉时长
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,x,p,q,i=1,sum,t,w;
int main(){
cin>>n>>x>>p>>q;
while(n--){
cin>>w;
if((x-t-w+sum)*q>=i*p*x&&x-t>w)t+=w;
else{
sum+=x-t;
i++;
long long l=ceil((q*(sum+x-w)-p*i*x)*1.0/(x*p-x*q));
if(l>0){
sum+=x*l;
i+=l;
}
t=w;
}
}
cout<<i;
}
P1148 拱猪计分
题意:求分数
思路:注释中
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct card
{
char type;//牌的种类
int point;//牌的点数
}c[100];
int ans[100];
int main()
{
int time=0,num,t=0,sco=0,hflag=0,sflag=0,dflag=0;//time用来统计总的牌数,t用来特判换行,sco用来储存分数,其他的几个用来检查有无特殊情况。
while(cin>>num)
{
time++;
for(int i=1;i<=num;i++)
cin>>c[i].type>>c[i].point;
for(int i=1;i<=num;i++)
if(c[i].type=='H') t++;
if(t==13) hflag=1;//即所有红心在一家
for(int i=1;i<=num;i++)
if(c[i].type=='S'&&c[i].point==12) sflag=1;//出现S12
for(int i=1;i<=num;i++)
if(c[i].type=='D'&&c[i].point==11) dflag=1;//出现D11
for(int i=1;i<=num;i++)
{
if(c[i].type=='C'&&c[i].point==10)
swap(c[i],c[num]);//把C10换到最后
if(hflag==1)//所有红心在一家的情况
{
if(sflag==1&&dflag==1) sco=500;
else
{
sco=200;
if(sflag==1) sco-=100;
if(c[i].type=='D'&&c[i].point==11) sco+=100;
}
}
else
{
if(c[i].type=='H')
{
if(c[i].point==1) sco-=50;
if(c[i].point==2) sco-=2;
if(c[i].point==3) sco-=3;
if(c[i].point==4) sco-=4;
if(c[i].point==5) sco-=5;
if(c[i].point==6) sco-=6;
if(c[i].point==7) sco-=7;
if(c[i].point==8) sco-=8;
if(c[i].point==9) sco-=9;
if(c[i].point==10) sco-=10;
if(c[i].point==11) sco-=20;
if(c[i].point==12) sco-=30;
if(c[i].point==13) sco-=40;
}
if(c[i].type=='S'&&c[i].point==12) sco-=100;
if(c[i].type=='D'&&c[i].point==11) sco+=100;
}
if(c[i].type=='C'&&c[i].point==10)
{
if(num==1) sco=50;//如果仅有这一张牌
else sco*=2;
}
}
ans[time]=sco;//把答案存进数组
t=0,sco=0,hflag=0,sflag=0,dflag=0;//变量全部重置
memset(c,0,sizeof(c));//清空储存牌的数组
}
for(int i=1;i<=time;i++)
{
if(i%4==1&&ans[i]==0&&ans[i+1]==0&&ans[i+2]==0&&ans[i+3]==0)//判断结束条件
break;
if(ans[i]>0) cout<<"+"<<ans[i]<<" ";//正数要加'+'
else cout<<ans[i]<<" ";//负数和0直接输出
if(i%4==0) cout<<endl;//每四张牌换行
}
return 0;
}