数据铁到std都过不去…
话说暴力真的可以出奇迹!:)
目录
1.Food Chain
- 因为有k-1条边,所以只可能是一棵树,即根节点是最高营养级的物种。bfs按营养级一层一层搜,之后再从叶子节点向上传递能量就行了。
- 这里的队其实有点像栈,bfs入队后并不出来,只是head头指针向后移动,最后是像栈一样弹出的。
看到数据量果断开启读入优化...
#include <cstdio>
#include <iostream>
using namespace std;
const int MAXN=2000005;
const long long P=32416190071;
long long w[MAXN];
int s[MAXN],yita[MAXN],h[MAXN],no,fa[MAXN];
bool use[MAXN];
struct line{
int to,next;
}edge[MAXN];
inline int read(){
char c; int x;
while(c=getchar(),c<'0' || '9'<c);
x=c-'0';
while(c=getchar(),'0'<=c && c<='9')
x=x*10+c-'0';
return x;
}
inline void add(int u,int v){
edge[++no].next=h[u];
h[u]=no;
edge[no].to=v;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Chain.in","r",stdin);
freopen("Chain.out","w",stdout);
#endif
int n=read(),tmpx,tmpy,cnt=0,head=0,tail=0,now,pos;
for(int i=1;i<n;++i){
tmpx=read(),tmpy=read();
fa[tmpy]=tmpx;
add(tmpx,tmpy);
yita[tmpy]=read();
use[tmpy]=true;
}
for(int i=1;i<=n;++i)
w[i]=read();
for(int i=1;i<=n;++i){
if(!use[i]){
pos=i;
s[++tail]=i;
break;
}
}
while(head<tail){
now=s[++head];
if(!h[now]) ++cnt;
else{
for(int i=h[now];i;i=edge[i].next)
s[++tail]=edge[i].to;
}
}
while(tail){
now=s[tail];
--tail;
w[fa[now]]=(w[fa[now]]+w[now]*yita[now]%P)%P;
}
cout<<cnt<<endl<<w[pos]<<endl;
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
2. So many prefix?
- dp+kmp.
- 考虑kmp中的f[i],代表最大的k(k!=i)使
c[1]c[2]…c[k]==c[i–k +1]c[i–k]…c[i]
成立,那么我们设dp[i]代表以i为前缀,即s[1]s[2]…s[i]
,内所有偶数子串出现的次数(包含本身)。 - 于是得到状态转移方程:
dp(i)={1+dp[f[i]]dp[f[i]]i%2==0 i%2==1
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN=200005;
int m,f[MAXN];
long long dp[MAXN];
char c[MAXN];
void getfail(){
m=strlen(c);
int j;
for(int i=1;i<m;++i){
j=f[i];
while(c[i]!=c[j] && j) j=f[j];
f[i+1]= c[i]==c[j] ? j+1:0;
}
}
long long work(){
long long ans=0;
for(int i=1;i<=m;++i){
if(~i&1) dp[i]=1;
dp[i]+=dp[f[i]];
ans+=dp[i];
}
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Prefix.in","r",stdin);
freopen("Prefix.out","w",stdout);
#endif
scanf("%s",c);
getfail();
cout<<work()<<endl;
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
3.Illegal Motor
- 很裸的分层图问题,建k+1个图。若u,v间有连边,则第i个的u和第i+1个图v’连一条0边(因为是无向图,所以v和u’也要连)。
- 之后从第一个图的s跑最短路(要用dijsktra,SPFA会被卡死…),ans=min{dis[ti]}。
#include <cstdio>
#include <queue>
using namespace std;
const int MAXN=10005*11,MAXM=50005*21<<1,INF=~0U>>1;
int head[MAXN],cnt,n,m,k,s,t;
bool use[MAXN];
struct list{
int dis,x;
list(){dis=INF;}
friend bool operator> (const list &a,const list &b){
return a.dis>b.dis;
}
}node[MAXN];
priority_queue<list,vector<list>,greater<list> > q;
struct line{
int to,next,len;
}edge[MAXM];
inline int read(){
char c; int x;
while(c=getchar(),c<'0' || '9'<c);
x=c-'0';
while(c=getchar(),'0'<=c && c<='9')
x=x*10+c-'0';
return x;
}
inline void add(int u,int v,int w){
edge[++cnt].next=head[u];
head[u]=cnt;
edge[cnt].to=v;
edge[cnt].len=w;
}
void build(){
int x,y,w;
for(int i=1;i<=m;++i){
x=read(),y=read(),w=read();
for(int j=0;j<k;++j){
add(x+n*j,y+n*j,w);
add(y+n*j,x+n*j,w);
add(x+n*j,y+n*(j+1),0);
add(y+n*j,x+n*(j+1),0);
}
add(x+n*k,y+n*k,w);
add(y+n*k,x+n*k,w);
}
}
void dijsktra(){
for(int i=1;i<=n*(k+1);++i)
node[i].x=i;
node[s].dis=0;
q.push(node[s]);
list tmp;
int u,v,w;
while(q.size()){
tmp=q.top();
q.pop();
u=tmp.x;
if(!use[u]){
use[u]=true;
for(int i=head[u];i;i=edge[i].next){
v=edge[i].to,w=edge[i].len;
if(node[v].dis>node[u].dis+w){
node[v].dis=node[u].dis+w;
q.push(node[v]);
}
}
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Motor.in","r",stdin);
freopen("Motor.out","w",stdout);
#endif
n=read(),m=read(),k=read();
s=read(),t=read();
build();
dijsktra();
int ans=INF;
for(int i=0;i<=k;++i)
ans=min(ans,node[t+n*i].dis);
printf("%d",ans);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
ps:谁知道第一段代码宏语句为啥红了…:(