爆零之路的起点…
考场上的代码有一个数组的下标敲错,然后爆零
自测几组数据竟然还过了…
emmmm
Code:
2018-10-01 19:51:01成功A掉
评价:普及+,提高-
思路:
首先很容易想到如何判断两条线有交点
就是在所给的字符串中找到两个一样的点
然后在这两个点之间搜索
记录两点之间所有点出现的次数,判断是否为偶数即可
然而这是片面的
我们需要找两个一样的点也是有限制的,我们要处理一下。
同时我们在记录交点的时候,不能单纯的凭借奇偶来判断,要采用特殊的方法
讲上面的那些废话只是因为基本思路比较重要.......
当然代码处理起来也特难受
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define size 100010
using namespace std;
string a;
int num[30],start[size],end[size],pos[size],posn[size],vis[size];
int sign[size],ans;
int main()
{
cin>>a;
int len=a.length();
for(int i=0;i<len;i++)
sign[i]=a[i]-96;
int tot=0;
for(int i=0;i<len;i++)
{
if(num[sign[i]]==0)
{
tot++;
start[tot]=i;
num[sign[i]]=1;
pos[sign[i]]=tot;
posn[i]=tot;
}
else
{
num[sign[i]]=0;
end[pos[sign[i]]]=i;
posn[i]=pos[sign[i]];
}
}
for(int i=1;i<=tot;i++)
{
int sum=0;
memset(vis,0,sizeof(vis));
for(int j=start[i]+1;j<end[i];j++)
{
if(vis[posn[j]]==0)
{
vis[posn[j]]=1;
sum++;
}
else
{
vis[posn[j]]=0;
sum--;
}
}
ans+=sum;
}
printf("%d",ans/2);
return 0;
}
纯净Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define size 100010
using namespace std;
string a;
int num[30],start[size],end[size],pos[size],posn[size],vis[size];
int sign[size],ans;
int main()
{
cin>>a;
int len=a.length();
for(int i=0;i<len;i++)
sign[i]=a[i]-96;
int tot=0;
for(int i=0;i<len;i++)
{
if(num[sign[i]]==0)
{
tot++;
start[tot]=i;
num[sign[i]]=1;
pos[sign[i]]=tot;
posn[i]=tot;
}
else
{
num[sign[i]]=0;
end[pos[sign[i]]]=i;
posn[i]=pos[sign[i]];
}
}
for(int i=1;i<=tot;i++)
{
int sum=0;
memset(vis,0,sizeof(vis));
for(int j=start[i]+1;j<end[i];j++)
{
if(vis[posn[j]]==0)
{
vis[posn[j]]=1;
sum++;
}
else
{
vis[posn[j]]=0;
sum--;
}
}
ans+=sum;
}
printf("%d",ans/2);
fclose(stdin);
fclose(stdout);
return 0;
}
不在状态,再次爆零…
跑最短路就可以了
跑的时候判断一下即可
良心的出题人并没有卡spfa
所以我们跑spfa
Code:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define size 5005
using namespace std;
bool special[size];
int n,m,q,k,ans;
int tot,head[size],ver[size],next[size],edge[size];
void add(int x,int y,int z,bool love)
{
tot++;
ver[tot]=y;
edge[tot]=z;
special[tot]=love;
next[tot]=head[x];
head[x]=tot;
}
bool vis[600];
int f[2001][601];
queue<int> qwq;
void spfa1()
{
memset(f,0x7f,sizeof(f));
f[0][1]=0;
qwq.push(1);
vis[1]=1;
while(!qwq.empty())
{
int cur=qwq.front();
qwq.pop();
vis[cur]=0;
for(int i=head[cur];i;i=next[i])
{
int x=ver[i];
for(int j=0;j+special[i]<=k;j++)
{
if(f[j][cur]==0x7f7f7f7f) break;
if(f[j+special[i]][x]>f[j][cur]+edge[i])
{
f[j+special[i]][x]=f[j][cur]+edge[i];
if(vis[x]==0)
{
vis[x]=1;
qwq.push(x);
}
}
}
}
}
}
void spfa2()
{
memset(f,0x7f,sizeof(f));
f[0][1]=0;
qwq.push(1);
vis[1]=1;
while(!qwq.empty())
{
int cur=qwq.front();
qwq.pop();
vis[cur]=0;
for(int i=head[cur];i;i=next[i])
{
int x=ver[i];
if(f[0][x]>f[0][cur]+edge[i])
{
f[0][x]=f[0][cur]+edge[i];
if(vis[x]==0)
{
vis[x]=1;
qwq.push(x);
}
}
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&q,&k);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z,0);
}
for(int i=1;i<=q;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z,1);
}
if(q>=k)
{
spfa1();
int ans=0x7f7f7f7f;
for(int i=0;i<=k;i++)
ans=min(ans,f[i][n]);
printf("%d",ans==0x7f7f7f7f?-1:ans);
}
else
{
spfa2();
printf("%d",f[0][n]);
}
return 0;
}
基础树形dp
//基础树形dp
f
[
i
]
f[i]
f[i]代表使以
i
i
i为根的树不连通的最小代价
易得转移方程
f
[
i
]
=
m
i
n
(
e
d
g
e
[
i
]
,
f
[
j
]
)
f[i]=min(edge[i],f[j])
f[i]=min(edge[i],f[j])
即使得这棵树与叶子结点不连通的方法有两种
一种是删除与叶子节点相连的边,即
e
d
g
e
[
i
]
edge[i]
edge[i]
一种是删除包括这些叶子结点的子树即
f
[
j
]
f[j]
f[j]
Code:
#include<iostream>
#include<cstring>
#include<cstdio>
#define size 100010
using namespace std;
int n,s,f[size];
bool vis[size];
int tot,ver[size*2],edge[size*2],head[size],next[size*2];
void add(int x,int y,int z)
{
tot++;
next[tot]=head[x];
edge[tot]=z;
ver[tot]=y;
head[x]=tot;
}
void dfs(int x)
{
vis[x]=1;
for(int i=head[x];i;i=next[i])
{
int y=ver[i];
if(vis[y]) continue;
dfs(y);
if(f[y]==0) f[x]+=edge[i];
else f[x]+=min(f[y],edge[i]);
}
}
int main()
{
scanf("%d%d",&n,&s);
for(int i=1;i<=n-1;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(s);
printf("%d",f[s]);
return 0;
}
emmmm
数论…
直接把阶乘求出来是不可能的,所以我们要从
n
n
n和
k
k
k的关系入手
对于
k
k
k进制下的数,要使其末尾为零,肯定要
k
k
k的因数相乘。
那么我们考虑将
k
k
k质因数分解
n
!
n!
n!含几个
k
k
k因数,然后将
k
k
k包含的该质因子的个数除以
n
!
n!
n!中包含该质因子的个数,然后选出这个最小值即可
证明:
对于样例
n
=
10
,
k
=
10
n=10,k=10
n=10,k=10来说
k
=
2
×
5
=
10
k=2\times5=10
k=2×5=10
n
!
n!
n!中包含8个2和2个5,则
n
!
n!
n!末尾有2个0,因为,其8个2除以
k
k
k的一个2,得到8,然后其2个5除以
k
k
k的一个5,得到2,即
n
!
n!
n!最多可以用两个2和两个5来组成k的倍数.
注意开long long!
Code:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const long long INF = ((1ll << 62) - 1 << 1) + 1;
long long n,k,s,tt;
long long tot1,tot2;
long long ans=INF;
int main()
{
scanf("%lld%lld",&n,&k);
s=sqrt(k);
for(int i=2;i<=s;i++)
{
if(k%i) continue;
tot1=0;tot2=0;
while(k%i==0)
{
tot1++;
k/=i;
}
tt=n;
while(tt)
{
tot2+=tt/i;
tt/=i;
}
ans=min(ans,tot2/tot1);
}
if(k>1)
{
tot2=0;
tt=n;
while(tt)
{
tot2+=tt/k;
tt/=k;
}
ans=min(ans,tot2);
}
printf("%lld",ans);
return 0;
}
T5T6 已死亡