T1

Description

给定一个n个点m条边的有向图,有k个标记点,要求从规定的起点按任意顺序经过所有标记点到达规定的终点,问最短的距离是多少。

Input

第一行5个整数n、m、k、s、t,表示点个数、边条数、标记点个数、起点编号、终点编号。

接下来m行每行3个整数x、y、z,表示有一条从x到y的长为z的有向边。

接下来k行每行一个整数表示标记点编号。

Output

输出一个整数,表示最短距离,若没有方案可行输出-1。

Sample Input

3 3 2 1 1

1 2 1

2 3 1

3 1 1

2

3

Sample Output

3

【样例解释】

路径为1->2->3->1。

Data Constraint

20%的数据n<=10。

50%的数据n<=1000。

另有20%的数据k=0。

100%的数据n<=50000,m<=100000,0<=k<=10,1<=z<=5000。

解题思路

考场上一时抽风写了个最短路套状压初值还没附好,50分。。正解应该是将必须经过的点两两之间的最短路求出来之后dfs

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define int long long using namespace std;
const int MAXN = 50005;
const int inf = 0x3f3f3f3f3f3f3f3f; int n,m,k,S,T,go[MAXN],ans=0x3f3f3f3f3f3f3f3f;
int head[MAXN],cnt,tot;
int to[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1];
int dis[15][MAXN],id[MAXN],dp[(1<<11)+5][15];
bool vis[MAXN],must[MAXN],use[MAXN];
queue<int> Q; inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} inline void add(int bg,int ed,int w){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt,val[cnt]=w;
} inline void spfa(int x){
memset(vis,false,sizeof(vis));
dis[++tot][x]=0;vis[x]=1;Q.push(x);
while(!Q.empty()){
int x=Q.front();Q.pop();
for(register int i=head[x];i;i=nxt[i]){
int u=to[i];
if(dis[tot][x]+val[i]<dis[tot][u]) {
dis[tot][u]=dis[tot][x]+val[i];
if(!vis[u]) {
vis[u]=1;
Q.push(u);
}
}
}
vis[x]=0;
}
} inline void dfs(int x,int now,int sum){
if(sum>ans) return;
if(now==k) {ans=min(ans,sum+dis[id[x]][T]);return;}
for(register int i=1;i<=k;i++){
if(use[i]) continue;
use[i]=1;
dfs(go[i],now+1,sum+dis[id[x]][go[i]]);
use[i]=0;
}
} signed main(){
memset(dp,0x3f,sizeof(dp));
memset(dis,0x3f,sizeof(dis));
n=rd();m=rd();k=rd();S=rd();T=rd();
for(register int i=1;i<=m;i++){
int x=rd(),y=rd(),z=rd();
add(x,y,z);
}
for(register int i=1;i<=k;i++){
int x=rd();must[x]=1;id[x]=i;go[i]=x;
spfa(x);
}
if(!must[S]) spfa(S),id[S]=k+1;
for(register int i=1;i<=k;i++){
memset(use,false,sizeof(use));
if(dis[id[S]][go[i]]==inf) continue;
use[i]=1;
if(must[S] && go[i]!=S)
dfs(go[i],2,dis[id[S]][go[i]]);
else if(!must[S])
dfs(go[i],1,dis[id[S]][go[i]]);
}
if(k==0) ans=dis[id[S]][T];
if(ans==inf) ans=-1;
cout<<ans<<endl;
return 0;
}

T2

Description

万老师听说某大国很流行穿越,于是他就想写一个关于穿越的剧本。

闲话休提。话说老师穿越到了某一个剑与魔法的大陆。因为如此这般,所以老师从维娜艾那里得到了预言。老师一共被告知了若干件按顺序结算的事件。这些事件分为两类:战役事件(CASE)、穿越回去事件(END)。战役事件可以选择是否参加,参加了之后会获得一定的金钱。每个END事件发生需要至少参加一定数量的战役事件。特别的是,END事件如果满足要求就会强制发生。老师希望在大陆玩个够,所以他要求只有最后一个END事件会发生。老师希望获得最多的金钱,所以求助于你。

Input

第一行一个数N,表示输入文件有多少行。

接下来每一行用空格隔开一个字符和一个整数。字符为“c”表示战役事件,接下来的整数表示这次涨RP顺带有多少钱;字符为“e”表示穿越回去事件,接下来的整数代表至少要涨多少RP。最后一个事件保证是END事件。

Output

第一行一个整数,最多金钱数目。

若不可能则输出-1。

Sample Input

5

c 10

c 12

e 2

c 1

e 2

Sample Output

13

Data Constraint

30%的数据满足 N<=20

60%的数据满足 N<=1,000

100%的数据满足 N<=200,000

每次涨RP事件赏金不超过10,000

穿越事件的要求不超过200,000

解题思路

最后的战役事件竟然能超了最后的end!!!我太菜了还以为能相等。。。写了两个小时的线段树+对拍结果0分。。又是一道由100 变成 0的好题。正解是优先队列+贪心。我用的线段树直接先排序,然后每次挑最大的相当于区间修改,从这个战役之后的第一个一直到倒数第二个这段区间-1。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm> using namespace std;
const int MAXN = 200005;
const int inf = 0x3f3f3f3f; int n,cnt1,cnt2,ans,mn[MAXN<<1];
int sum[MAXN<<1],lazy[MAXN<<1]; struct Data{
int id,a;
}data[3][MAXN]; inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} inline bool cmp(Data A,Data B){
return A.a>B.a;
} inline void pushdown(int x,int ln,int rn){
lazy[x<<1]+=lazy[x];
lazy[x<<1|1]+=lazy[x];
sum[x<<1]+=ln*lazy[x];
sum[x<<1|1]+=rn*lazy[x];
mn[x<<1]+=lazy[x];
mn[x<<1|1]+=lazy[x];
lazy[x]=0;
} inline void build(int x,int l,int r){
if(l==r){
sum[x]=data[2][l].a;
mn[x]=data[2][l].a;
lazy[x]=0;
return ;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
sum[x]=sum[x<<1]+sum[x<<1|1];
mn[x]=min(mn[x<<1],mn[x<<1|1]);
} inline void update(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R){
sum[x]+=k;mn[x]+=k;lazy[x]+=k;
return ;
}
int mid=l+r>>1;
if(lazy[x]) pushdown(x,mid-l+1,r-mid);
if(mid>=L) update(x<<1,l,mid,L,R,k);
if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
sum[x]=sum[x<<1]+sum[x<<1|1];
mn[x]=min(mn[x<<1],mn[x<<1|1]);
} inline int query(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return mn[x];
int ret=0x3f3f3f3f;
int mid=l+r>>1;
if(lazy[x]) pushdown(x,mid-l+1,r-mid);
if(mid>=L) ret=min(ret,query(x<<1,l,mid,L,R));
if(mid<R) ret=min(ret,query(x<<1|1,mid+1,r,L,R));
return ret;
} int main(){
n=rd();
for(register int i=1;i<=n;i++){
char c;cin>>c;int x=rd();
if(c=='c') data[1][++cnt1].a=x,data[1][cnt1].id=i;
else data[2][++cnt2].a=x,data[2][cnt2].id=i;
}
build(1,1,cnt2);
sort(data[1]+1,data[1]+1+cnt1,cmp);
for(register int i=1;i<=cnt1;i++){
int ID=data[1][i].id;int x=data[1][i].a;
int l=1,r=cnt2;int now;
while(l<=r){
int mid=l+r>>1;
if(data[2][mid].id<ID) l=mid+1;
else {
now=mid;
r=mid-1;
}
}
int res;
if(now>cnt2-1) res=inf;
else res=query(1,1,cnt2,now,cnt2-1);
if(res>1 || now==cnt2){
ans+=x;
if(now!=cnt2)
update(1,1,cnt2,now,cnt2-1,-1);
}
}
cout<<ans<<endl;
return 0;
}

T3

Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits

Goto ProblemSet

Description

平面上有n个点,求出用这些点可以构成的三角形数。

Input

第一行一个整数n。

接下来n行,每行两个整数,表示点的坐标。

Output

输出仅一个整数,表示所求答案。

Sample Input

5

0 0

1 1

1 -1

-1 -1

-1 1

Sample Output

8

Data Constraint

对于50%的数据,n<=300。

对于100%的数据,n<=3000,坐标的绝对值不超过10^4,保证没有重合的点。

解题思路

这道题跟以前做过的数三角形好像啊,结果还是打的暴力。。用容斥的思想,每次枚举一个点,然后枚举其余点算斜率,之后排个序用组合数学。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define int long long using namespace std;
const int MAXN = 3005;
const double inf = 1e10+1;
const double eps = 1e-12; int n,x[MAXN],y[MAXN],sum,cnt;
double slp[MAXN]; inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} signed main(){
freopen("triangle.in","r",stdin);
freopen("triangle.out","w",stdout);
n=rd();sum=n*(n-1)*(n-2)/6;
for(register int i=1;i<=n;i++)
x[i]=rd(),y[i]=rd();
for(register int i=1;i<=n;i++){
memset(slp,0,sizeof(slp));cnt=0;
for(register int j=i+1;j<=n;j++){
if(y[i]==y[j]) slp[++cnt]=inf;
else if(x[i]==x[j]) slp[++cnt]=-inf;
else slp[++cnt]=(double)(x[i]-x[j])/(y[i]-y[j]);
}
sort(slp+1,slp+1+cnt);
int now=1;slp[0]=-inf-5;
for(register int j=1;j<=cnt;j++){
if(fabs(slp[j]-slp[j-1])>eps){
sum-=now*(now-1)/2;
now=1;
}
else now++;
}
sum-=now*(now-1)/2;
}
printf("%lld",sum);
return 0;
}

最新文章

  1. TortoiseGit安装详解
  2. android-studio的gradle plugin配置相关的一些记录
  3. [Tool] Chrome内的本地网页,使用XMLHttpRequest读取本地档案
  4. linux ssh 登录同时执行其他指令
  5. Kibana安装及部署
  6. GCD使用dispatch_semaphore_t创建多线程网络同步请求
  7. ModifyInfo.aspx.cs代码
  8. LinQ的一些基本语句
  9. UIBezierPath IOS贝塞尔曲线
  10. C#中保留两位小数但不四舍五入的最优做法
  11. JQuery插件开发 - 模板
  12. 获取c++ edit控件内容
  13. (九)打印机驱动设置—USB接口的设置
  14. Windows 2008 server R2安装.NET Framework4时提示“灾难性故障”解决
  15. python之第一个例子hello world
  16. Unity3d该物业(Attributes)整理
  17. php5.4下配置zend guard loader
  18. android Spinner控件详解
  19. Linux 学习笔记_12_文件共享服务_3_NFS网络文件服务
  20. java学习笔记10-方法

热门文章

  1. System.Web.Mvc.RedirectResult.cs
  2. Jeecg-Boot前后端分离,针对敏感数据,加密传递方案
  3. springboot整合aop实现网站访问日志记录
  4. 进程外Session---数据库Session的配置
  5. 04-6-queryselect
  6. tensorflow/models 下面的data_augment_options的random_image_scale
  7. Java基础知识(面试问题1)
  8. 最大似然估计(Maximum likelihood estimation)
  9. 安装配置git服务
  10. @NotNull,@NotBlank和 @NotEmpty使用