描述:
MWH寒假外出旅游,来到了S国。S国划分为N个省,第i个省有Ti座城市,编号分别为Ci1,Ci2,……CiTi(各省城市编号不会重复)。所有城市间有M条双向的道路连接,从任意一个城市出发,可到达一切城市,每条道路均须收费。
此时恰逢春运期间,S国交通运输局采取了优惠措施。当一条路的路费在[L..R]区间时,可免去。同时,每个省也有优惠措施,第i个省内的每条道路路费收其Xi%,连接第i个省和第j个省的每条道路路费收其(Xi%+Xj%)/2。
MWH想从城市s走到城市t,请求出一对L,R,确保:
- MWH能免费到达目的地;
- L≤R;
- L、R均为整数;
- L尽可能地大,R在满足L最大的前提下最小。
输入
第一行两个整数N,M。
接下来M行,每行三个整数,u、v、w,表示连接u、v的道路需收费w。
接下来N行,第i+M+1行有一个整数Ti,后面Ti个整数,分别是Ci1..CiTi(所有城市编号保证按正整数顺序给出1.. Ti)。
下一行N个整数X1..Xi。
最后一行,两个整数,s、t。
输出
一行两个整数,如题,L和R。
样例
输入 输出
3 7 2 6 1 2 3 5 2 8 1 3 7 5 4 5 2 4 9 3 5 10 3 4 2 2 1 2 1 3 2 4 5 30 50 60 1 5
n<=5000 m<=100000 城市<=50000
注意:因每条道路由各省的交通运输局直接管辖,所以每条道路的路费必须先得到省级优惠,再得到国家级优惠。
杨神犇提供显然思路,跑一个最大生成树,s->t路径上最小边就是l,然后跑一个最小生成树,强行使刚才的最小边加入树中,s->t路径上最大边就是r,输出即可。
我的思路是先二分一个l,权值在l~15000的边保留,看s->t是否在同一联通块,并查集判断即可,r同理。
我的代码:
#include <cstdio> #include <algorithm> #include <ctime> using namespace std; const int N=100005; int n,m; int xx[N],yy[N],block[50005],ss,t; int dl,dr=16000,maxx; double van[N],zk[50005]; inline int read() { char k=0;char ls;ls=getchar(); for(;ls<'0'||ls>'9';k=ls,ls=getchar()); int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0'; if(k=='-')x=0-x;return x; } struct bcj { int fa[50005]; inline void be(){for(int i=1;i<=maxx;i++)fa[i]=i;} int f(int x){return fa[x]=(fa[x]==x)?x:f(fa[x]);} int u(int x,int y){fa[f(y)]=f(x);} }s; inline bool gay1(int x) { s.be(); for(int i=1;i<=m;++i) { if(x<=van[i]) s.u(xx[i],yy[i]); } if(s.f(ss)==s.f(t)) return true; return false; } inline void fuck1() { int l=0,r=16000,ans; while(l<r) { int mid=(l+r)>>1; if(gay1(mid)) l=mid+1,ans=mid; else r=mid; } dl=ans; } inline bool gay2(int x) { s.be(); for(int i=1;i<=m;++i) { if(dl<=van[i]&&van[i]<=x) s.u(xx[i],yy[i]); } if(s.f(ss)==s.f(t)) return false; return true; } inline void fuck2() { int l=0,r=16000,ans; while(l<r) { int mid=(l+r)>>1;//printf("mid=%d ",mid); if(gay2(mid)) l=mid+1;//,printf("jzsb:l=%d r=%d mid=%d ",l,r,mid); else r=mid,ans=mid;//,printf("ljjz:l=%d r=%d mid=%d ",l,r,mid); } dr=ans; } int main() { freopen("trip.in","r",stdin); freopen("trip.out","w",stdout); // double stt=clock(); n=read();m=read(); for(int i=1;i<=m;++i){xx[i]=read(),yy[i]=read(),scanf("%lf",&van[i]);maxx=max(max(xx[i],yy[i]),maxx);} for(int i=1,T,x;i<=n;++i) { T=read(); while(T--) x=read(),block[x]=i; } for(int i=1;i<=n;++i) { scanf("%lf",&zk[i]); zk[i]/=(double)100; } for(int i=1;i<=m;++i) { int jzoj=block[xx[i]]; int laji=block[yy[i]]; if(jzoj==laji) van[i]*=zk[jzoj]; else van[i]*=(zk[jzoj]+zk[laji])/2; } /*for(int i=1;i<=m;++i) { printf("%d %d %lf ",xx[i],yy[i],van[i]); }*/ ss=read();t=read(); fuck1();fuck2(); printf("%d %d",dl,dr); // double eed=clock(); // printf(" %.2lfms",eed-stt); }
Data Constraint
对于10%的数据:1<=n<=3
对于20%的数据,1<=n<=9
对于30%的数据:1<=n<=18,1<=k<=10^6
对于60%的数据:1<=n<=18
对于80%的数据:1<=n<=100,1<=k<=10^100
对于90%的数据:1<=n<=1000,1<=k<=10^1000
对于100%的数据:1<=n<=100000,1<=k<=min(10^20000,n!)
显然过90%数据高精模拟即可。100%数据发现1<=k<=min(10^20000,n!),大概在n>=6000左右开始模拟即可。
具体先看k的值,来确定第一位放那个:
如:输入 4 8
考虑4的全排列第一位放什么,假如第一个放1,后面3个有(n-1)!种放法。
所以应该放的为k mod (n - i +1)! / (n - i)! (从大到小枚举i)
然后 k mod (n - i +1)! / (n - i)!=k div (n - i)! mod (n - i + 1)
暴力高精除低精,高精取膜,int64 压位即可。(表示没写);
对于一个正整数N,存在一个正整数T(0<T<N),使得
的值是正整数。
小X给出N,让小Y给出所有可能的T。如果小Y不回答这个神奇的大佬的简单数学题,他学神的形象就会支离破碎。所以小Y求你帮他回答小X的问题。 (n<=10^14)
随便推公式即可(感谢van老师教的数学)。
设
[n-(t/2)]/(n-t)=k
1/2+n/[2(n-t)]=k
1+n/(n-t)=2k
就是让n/(n-t)为奇数即可,
枚举n的约数即可。(题解只是提示,细节不多提)
#include <cstdio> #include <algorithm> #include <cmath> using namespace std; long long n; long long a[10000005],b[10000005]; long long cnt1,cnt2; bool flag; int main() { freopen("math.in","r",stdin); freopen("math.out","w",stdout); scanf("%lld",&n); if(n==1||n==0||n==2) {printf("0");return 0;} int sq=sqrt(n); for(long long i=1;i<=sq;++i) { if(n%i==0) { // printf("%lld ",n%i); flag=true; long long j=n/i; // printf("%lld %lld ",i,j); if((j&1)&&i!=n) { b[++cnt2]=n-i; } if((i&1)&&j!=n) { a[++cnt1]=n-j; } } } if(flag==false) { printf("1 %lld",n-1); } else { printf("%lld ",cnt1+cnt2); for(int i=1;i<=cnt1;++i) printf("%lld ",a[i]); for(int i=cnt2;i>=1;--i) printf("%lld ",b[i]); } }
Data Constraint
对于100%的数据,1 ≤ N, M, K ≤ 5000。
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=5005; const int INF=0x3f3f3f3f; int dp[N<<1][N]; int hzh[N<<1][N]; int n,m,kk; int a[N],b[N]; int main() { freopen("vode.in","r",stdin); freopen("vode.out","w",stdout); scanf("%d%d%d",&n,&m,&kk); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); } for(int i=n+1;i<=m+n;++i) { a[i]=a[i-n]; } //memset(dp,INF,sizeof dp); for(int i=1;i<=m;++i) dp[i][m]=0; for(int i=n+m-1;i>=1;--i) { if(a[i]!=a[i+1]) { for(int j=m-1;j>=1;--j) { bool flag=false; //for(int k=j+1;k<=j+kk&&k<=m;++k){if(dp[i+1][k]==1) flag=true;} if(hzh[i+1][j+1]-hzh[i+1][min(m,j+kk)+1]>0) flag=true; if(flag==true) dp[i][j]=0; else dp[i][j]=1; hzh[i][j]=hzh[i][j+1]+dp[i][j]; } } else { for(int j=m-1;j>=1;--j) { bool flag=false; //for(int k=j+1;k<=j+kk&&k<=m;++k){if(dp[i+1][k]==1) flag=true;} if(hzh[i+1][j+1]-hzh[i+1][min(m,j+kk)+1]>0) flag=true; if(flag) dp[i][j]=1; else dp[i][j]=0; hzh[i][j]=hzh[i][j+1]+dp[i][j]; } } } for(int i=1;i<=n;++i) { bool flag=false; for(int j=1;j<=kk;++j) { if(dp[i][j]) {printf("%d ",a[i]);flag=true;break;} } if(!flag) printf("%d ",a[i]^1); } }
1 #include <cstdio> 2 #include <algorithm> 3 #include <queue> 4 #include <cstring> 5 6 using namespace std; 7 const int N=250005; 8 const int M=5000000; 9 const int INF=0x3f3f3f3f; 10 11 struct data 12 { 13 int v,nxt,val; 14 }edge[M]; 15 int cnt,alist[N]; 16 inline void add(int u,int v,int val=1){edge[++cnt]=(data){v,alist[u],val},alist[u]=cnt;} 17 int n,m,st,ed; 18 int mmp[505][505]; 19 20 inline void fuck(int x,int y) 21 { 22 int num=(y-1)*m+x; 23 if(mmp[x][y+1]==1) {add(y*m+x,num);} 24 if(mmp[x][y-1]==1) {add((y-2)*m+x,num);} 25 if(mmp[x-1][y]==1) {add(num-1,num);} 26 if(mmp[x+1][y]==1) {add(num+1,num);} 27 28 int a1,b1,c1,d1,dd=INF; 29 for(int i=x+1,temp=0;i<=m;++i) 30 { 31 temp++; 32 if(mmp[i][y]==0) {a1=(y-1)*m+i-1,dd=min(temp,dd);break;} 33 } 34 35 for(int i=x-1,temp=0;i>=1;--i) 36 { 37 temp++; 38 if(mmp[i][y]==0) {b1=(y-1)*m+i+1,dd=min(temp,dd);break;} 39 } 40 41 for(int i=y+1,temp=0;i<=n;++i) 42 { 43 temp++; 44 if(mmp[x][i]==0) {c1=(i-2)*m+x,dd=min(temp,dd);break;} 45 } 46 47 for(int i=y-1,temp=0;i>=1;--i) 48 { 49 temp++; 50 if(mmp[x][i]==0) {d1=(i)*m+x,dd=min(temp,dd);break;} 51 } 52 add(num,a1,dd);add(num,b1,dd);add(num,c1,dd);add(num,d1,dd); 53 } 54 55 bool vis[N]; 56 int dis[N]; 57 struct nod 58 { 59 int num,val; 60 friend bool operator <(nod a,nod b){return a.val>b.val;} 61 }; 62 inline void dj(int x) 63 { 64 priority_queue<nod> q;memset(dis,INF,sizeof dis); 65 nod pack=(nod){x,0}; 66 dis[x]=0;q.push(pack); 67 while(!q.empty()) 68 { 69 int now=q.top().num;q.pop(); 70 if(vis[now]) continue; 71 vis[now]=true; 72 for(int i=alist[now];i;i=edge[i].nxt) 73 { 74 int v=edge[i].v; 75 int val=edge[i].val; 76 if(dis[now]+val<dis[v]) 77 { 78 dis[v]=dis[now]+val; 79 nod pack=(nod){v,dis[v]}; 80 q.push(pack); 81 } 82 } 83 } 84 } 85 int main() 86 { 87 freopen("portal.in","r",stdin); 88 freopen("portal.out","w",stdout); 89 scanf("%d%d",&n,&m); 90 for(int j=1;j<=n;++j) 91 { 92 for(int i=1;i<=m;++i) 93 { 94 char c; 95 scanf(" %c",&c); 96 if(c=='#') mmp[i][j]=0; 97 else if(c=='.') mmp[i][j]=1; 98 else if(c=='C') mmp[i][j]=1,st=(j-1)*m+i; 99 else if(c=='F') mmp[i][j]=1,ed=(j-1)*m+i; 100 } 101 } 102 for(int i=2;i<m;++i) 103 { 104 for(int j=2;j<n;++j) 105 { 106 if(mmp[i][j]) fuck(i,j); 107 } 108 } 109 dj(st); 110 if(dis[ed]!=INF) printf("%d",dis[ed]); 111 else printf("nemoguce"); 112 }
大意:挺好理解的;
卍解:
对于m-i+1的倍数的点会在第i天连边,