爆零了...爽到
T1 题意简述:jzoj3470
解题思路:k遍dijkstra或SPFA+爆搜即可。由于k只有10,因此比状压dp还要快些。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #define INF 0x3f3f3f3f3f3f3f3f #define ll long long using namespace std; ll n,m,k,s,t,cnt,ans=INF,head[50001]; ll mp[50001],pnt[11],len[20][20]; ll dis[50001],vis[50001]; struct uio{ ll nxt,to,val; }edge[100001]; void add(ll x,ll y,ll z) { edge[++cnt].nxt=head[x]; edge[cnt].to=y; edge[cnt].val=z; head[x]=cnt; } void spfa(ll x) { memset(dis,0x3f,sizeof(dis)); queue<ll> que; while(!que.empty()) que.pop(); dis[x]=0; vis[x]=1; que.push(x); while(!que.empty()) { ll now=que.front(); que.pop(); vis[now]=0; for(ll i=head[now];i;i=edge[i].nxt) { ll y=edge[i].to; if(dis[y]>dis[now]+edge[i].val) { dis[y]=dis[now]+edge[i].val; if(!vis[y]) vis[y]=1,que.push(y); } } } } void dfs(ll x,ll now,ll l) { if(l>ans) return; if(x==k) { ans=min(ans,l+len[now][k+1]); return; } for(ll i=1;i<=k;i++) if(!vis[i]&&i!=now&&len[now][i]!=INF) vis[i]=1,dfs(x+1,i,l+len[now][i]),vis[i]=0; } int main() { scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&s,&t); for(ll i=1;i<=m;i++) { ll u,v,w; scanf("%lld%lld%lld",&u,&v,&w); add(u,v,w); } for(ll i=1;i<=k;i++) { scanf("%lld",&pnt[i]); mp[pnt[i]]=++mp[0]; } spfa(s); for(ll i=1;i<=k;i++) len[0][mp[pnt[i]]]=dis[pnt[i]]; if(!k) { if(dis[t]==INF) printf("-1 "); else printf("%lld ",dis[t]); return 0; } for(ll i=1;i<=k;i++) { spfa(pnt[i]); len[mp[pnt[i]]][k+1]=dis[t]; for(ll j=1;j<=k;j++) len[mp[pnt[i]]][mp[pnt[j]]]=dis[pnt[j]]; } dfs(0,0,0); if(ans==INF) printf("-1 "); else printf("%lld ",ans); return 0; }
T2 题意简述:jzoj3487
解题思路:小根堆维护所有事件即可。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #include<vector> #define INF 0x3f3f3f3f3f3f3f3f #define ll long long using namespace std; int n,ans; priority_queue<int,vector<int>,greater<int> > que; int main() { scanf("%d ",&n); for(int i=1;i<n;i++) { char c;int u; scanf("%c %d ",&c,&u); if(c=='c') que.push(u); else while(que.size()>=u) que.pop(); } char c;int u; scanf("%c %d",&c,&u); if(que.size()<u) {printf("-1 ");return 0;} while(!que.empty()) ans+=que.top(),que.pop(); printf("%d ",ans); return 0; }
T3 题意简述:jzoj3493
解题思路:枚举每个点,把其它点与这个点的斜率计算出来,将斜率相同的合并,计算组合数,用总方
案数减去计算出的组合数即可。
如何去重?只需在第二重循环时只枚举i+1~n的点且只把包含i的不合法情况去除即可。
考虑以下例子:编号为1 2 3 4的点排成一条直线。
枚举到1时,只把包含1的不合法情况去除。在本例子中,即去除(1,2,3)(1,2,4)(1,3,4)。
枚举到2时,只把包含2的不合法情况去除。在本例子中,即去除(2,3,4)。
以此类推,只需计算C(n,3)-∑(i=1~n)∑(j=i+1~n)C(k,2) 其中k表示相同斜率的数量。
感谢ErkkiErkko大佬和Menteur_Hxy大佬!!!
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define INF 0x3f3f3f3f3f3f3f3f #define ll long long using namespace std; ll n,cnt,ans; double k[10001],a[10001],b[10001]; int main() { freopen("triangle.in","r",stdin); freopen("triangle.out","w",stdout); scanf("%lld",&n); for(ll i=1;i<=n;i++) scanf("%lf%lf",&a[i],&b[i]); for(ll i=1;i<=n;i++) { cnt=0,memset(k,0xc0,sizeof(k)); for(ll j=i+1;j<=n;j++) if(a[i]==a[j]) k[++cnt]=INF; else k[++cnt]=(b[j]-b[i])/(a[j]-a[i]); sort(k+1,k+1+cnt); ll tmp=1; for(ll j=2;j<=cnt+1;j++) if(k[j]==k[j-1]) tmp++; else ans+=tmp*(tmp-1)/2,tmp=1; } printf("%lld",n*(n-1)*(n-2)/6-ans); return 0; }