王國道路(圖論)
*現在國王要建造道路,使得建造後的道路能夠使所有城市兩兩能夠相連通。
並且使得所有城市到首都一號城市的距離之和最小。
兩個城市間一條路徑的距離等於這條路徑上道路的最大值。兩個城市間的距離等於城市間的最短路徑。*
這道題坑啊
比賽結束前10min才解釋題意(雖然延時30min)
因爲我一開始打的是kruskal
所以腦補了一下記錄每個並查集的大小
在合併的時候更新答案
但是由於時間太緊
沒有打出來
下面是正解(最快)
每次取出隊列中的節點更新其他節點的答案
Spfa(883ms)
#include<cstdio>
#include<iostream>
#include<queue>
#define INF 2147483647
#define N 2010
using namespace std;
typedef long long LL;
LL ans;
queue<int>Q;
struct Edge{
int p,q,o,n;
}b[N*N];
int n,m,p,q,o,u,v,s,t,num,h[N],d[N];
bool bo[N];
void ljb(int p,int q,int o){
b[++num].n=h[p];
h[p]=num;
b[num].p=p;
b[num].q=q;
b[num].o=o;
}
void Spfa(){
int x,y;
while(!Q.empty()){
x=Q.front(); Q.pop();
bo[x]=0;
for(int i=h[x];i!=0;i=b[i].n){
y=b[i].q;
if(max(d[x],b[i].o)<d[y]){
d[y]=max(d[x],b[i].o);
if(!bo[y]){
bo[y]=1;
Q.push(y);
}
}
// printf("%d %d %d %d\n",x,y,d[x],d[y]);
}
}
}
int main(){
freopen("data.txt","r",stdin);
freopen("2.txt","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&p);
if(i!=j)ljb(i,j,p);
}
}
for(int i=1;i<=n;i++)if(i!=1)d[i]=INF;
Q.push(1);
bo[1]=1;
Spfa();
// for(int i=1;i<=n;i++)printf("%d ",d[i]);
// printf("\n");
for(int i=1;i<=n;i++)ans+=d[i];
cout<<ans<<'\n';
}
我的蒟蒻kruskal
Kruskal(1008ms)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 2010
typedef long long LL;
using namespace std;
int f[N],h[N],num,n,p,q,s[N];
LL ans;
struct edge{
int u,v,w,n;
}e[N*N/2];
int fa(int x){
if(f[x]!=x)f[x]=fa(f[x]);
return f[x];
}
void ljb(int p,int q,int o){
e[++num].n=h[p];
h[p]=num;
e[num].u=p;
e[num].v=q;
e[num].w=o;
}
bool cmp(edge p,edge q){
return p.w<q.w;
}
void kruskal(){
sort(e+1,e+num+1,cmp);
int t=0;
for(int i=1;i<=num;i++){
p=e[i].u;
q=e[i].v;
if(fa(p)==fa(q))continue;
if(f[p]==1)ans+=(LL)s[f[q]]*e[i].w;
else if(f[q]==1)ans+=(LL)s[f[p]]*e[i].w;
if(f[q]!=1){
s[f[p]]+=s[f[q]];
f[f[q]]=f[p];
}
else {
s[f[q]]+=s[f[p]];
f[f[p]]=f[q];
}
if(++t==n-1)break;
}
cout<<ans<<'\n';
}
int main(){
freopen("data.txt","r",stdin);
freopen("1.txt","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
f[i]=i;
s[i]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&p);
if(j>i)ljb(i,j,p);
}
}
kruskal();
}
來自xyl的
他首先kruskal一遍
然後dfs找每個點到首都的距離
求和就行了
kruskal+dfs(1213ms)from xyl
#include <cstdio>
#include <algorithm>
#define maxn (2000+10)
using namespace std;
int f[maxn],vis[maxn],g,g2,ans,p,n,m,head[maxn],mp[maxn][maxn];
struct xx
{
int u,v,next,q;
}b[maxn*maxn<<1],c[maxn<<1];
void add(int u,int v,int q)
{
b[++g]=(xx){u,v,head[u],q};
head[u]=g;
}
void add2(int u,int v,int q)
{
c[++g2]=(xx){u,v,head[u],q};
head[u]=g;
}
void dfs(int x,int tmp)
{
ans+=tmp;
vis[x]=1;
for (int i=head[x];i;i=b[i].next)
{
int v=b[i].v;
if (vis[v]) continue;
dfs(v,max(tmp,b[i].q));
}
return ;
}
int _find(int x)
{
return x==f[x]?x:f[x]=_find(f[x]);
}
int cmp(xx A,xx B)
{
return A.q<B.q;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
scanf("%d",&mp[i][j]);
for (int i=1;i<=n;++i)
for (int j=i+1;j<=n;++j)
add(i,j,mp[i][j]),add(j,i,mp[i][j]);
sort(b+1,b+1+g,cmp);
for (int i=1;i<=n;++i) head[i]=0,f[i]=i;
for (int i=1;i<=g;++i)
{
if (p==n-1) break;
int t1=_find(b[i].u);
int t2=_find(b[i].v);
if (t1!=t2) add(b[i].u,b[i].v,b[i].q),add(b[i].v,b[i].u,b[i].q),f[t1]=t2,++p;
}
vis[1]=1;
for (int i=head[1];i;i=b[i].next)
dfs(b[i].v,b[i].q);
printf("%d",ans);
return 0;
}
數位變換
首先k進制下N=xxxxxxx(末尾前的幾位)ddddddd(末尾的多少個d)
移項:N-d=xxxxxxxddddddd0
N-d=0(mod k)
所以k是N-d的因子
枚舉就行了
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
int p,ans,m;
LL n,num;
int Solve(LL x,LL k,int m){
if(k==1)return 0;
// cout<<x<<' '<<k<<'\n';
int cnt=0;
while(x!=0){
if(x%k==m)cnt++;
else return cnt;
x/=k;
}
return cnt;
}
int main(){
while(scanf("%lld%d",&n,&m)==2){
ans=0;
num=2;
// for(LL i=max(2,m+1);i<=n+1;i++){
for(LL i=1;i<=sqrt(n-m);i++){
if((n-m)%i!=0)continue;
p=Solve(n,i,m);
// cout<<n<<' '<<i<<' '<<p<<'\n';
if(ans<p||(ans==p&&num>i)){
ans=p;
num=i;
}
p=Solve(n,(n-m)/i,m);
// cout<<n<<' '<<(n-m)/i<<' '<<p<<'\n';
if(ans<p||(ans==p&&num>(n-m)/i)){
ans=p;
num=(n-m)/i;
}
}
cout<<num<<' '<<ans<<'\n';
}
}
股票傳說
滿分暴力加優化
#include<cstdio>
#include<iostream>
#define N 100010
using namespace std;
typedef long long LL;
LL d[N];
int a[N],n,m,f;
int main(){
freopen("data.txt","r",stdin);
scanf("%d%d%d",&n,&m,&f);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
d[0]=m;
for(int i=1;i<=n;i++){
d[i]=d[i-1];
for(int j=1;j<i;j++)d[i]=max(d[i],d[j]+(d[j]-f)/a[j]*(a[i]-a[j])-2*f);
}
cout<<d[n]<<'\n';
}
正解
#include<cstdio>
#include<iostream>
#define N 100010
using namespace std;
typedef long long LL;
LL d[N],a[N],b[N];
int n,m,f,p;
int main(){
scanf("%d%d%d",&n,&m,&f);
d[0]=m;
for(int i=1;i<=n;i++){
scanf("%d",&p);
d[i]=max(d[i-1],a[i-1]*p-f+b[i-1]);
if((d[i-1]-f)/p>a[i-1]||((d[i-1]-f)/p==a[i-1]&&(d[i-1]-f)%p>b[i-1])){
a[i]=(d[i-1]-f)/p;
b[i]=(d[i-1]-f)%p;
}
else {
a[i]=a[i-1];
b[i]=b[i-1];
}
}
cout<<d[n];
}
完美正解:
斜率優化
然後cdq分治(或splay)維護一個凸包