str —2992
思路:染色,将每个连通的’.’依依标记id和对应的个数sum。那么答案就是每个’*’的四个方向的连通块sum和。However,每次memset mark[][](判重)是O(n^2)的,所以会超时,也就是只需要for过来…
subpal —2993
思路:区间dp,和完美队形一模一样,但这是求可行的方案数,那么就前缀和再维护一下dp即可。(然而今天就炸在此题,最后无聊把代码放结构体里,结果int main里外都打了int n…)
#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define N 2005
#define INF 0x3f3f3f3f
#define LL long long
#define P 100007
// LL mod
using namespace std;
int n,m;
char s[N];
int ans,sum;
int dp[N];
void Add(int &a,int b){a=(a+b)%P;}
struct P100{
void solve(){
REP(i,1,n){
int cnt=0;
DREP(j,n,i){
Add(cnt,dp[j]);
if(s[i]==s[j]){
dp[j]=cnt+1;
if(dp[j]>P) dp[j]-=P;
}
}
}
REP(i,1,n) Add(ans,dp[i]);
cout<<ans<<endl;
}
}p100;
int main(){
scanf("%s",s+1);
n=strlen(s+1);
p100.solve();
return 0;
}
tree —2948
思路:与2968神似,也是询问和维护最值,离线来做。那么先求最小生成树,并mark有用的边,最后倍增一样的套路(当然也可以一个一个up上去,考试没有时间写倍增了…)
#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define N 50005
#define M 200005
#define INF 0x3f3f3f3f
#define LL long long
#define P 100007
// LL mod 调试 文件名
using namespace std;
int n,m;
bool mark[M];
int fa[N],D[N];
int Id[M],res[M];
struct edge{
int from,to,cost,id;
bool operator<(const edge &a)const{
return cost<a.cost;
}
}es[M];
struct node{
int to,cost,id;
};
vector<node>E[N];
int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
struct P50{
bool check(){
REP(i,2,n)if(fa[i]!=fa[i-1])return 0;
return 1;
}
int Kruskal(int w){
int res=0;
REP(i,1,n)fa[i]=i;
REP(i,1,m){
if(es[i].id==w)continue;
int x=Find(es[i].from),y=Find(es[i].to);
if(x==y)continue;
fa[x]=y;
res+=es[i].cost;
}
REP(i,1,n)fa[i]=Find(i);
if(!check())return -1;
return res;
}
void solve(){
REP(i,1,m){
int ans=Kruskal(i);
printf("%d\n",ans);
}
}
}p50;
void chkmin(int &x,int y){if(!x || x>y)x=y;}
struct P100{
int sum,ans;
struct Tree{
int fa,id;
}tree[N];
void dfs(int x,int f,int dep){
REP(i,0,E[x].size()-1){
node y=E[x][i];
if(y.to==f)continue;
D[y.to]=dep+1;
tree[y.to]=(Tree){x,y.id};
dfs(y.to,x,dep+1);
}
}
void Kruskal(){
REP(i,1,n)fa[i]=i;
REP(i,1,m){
int x=Find(es[i].from),y=Find(es[i].to);
if(x==y)continue;
fa[x]=y;
ans+=es[i].cost;
E[es[i].from].push_back((node){es[i].to,es[i].cost,es[i].id});
E[es[i].to].push_back((node){es[i].from,es[i].cost,es[i].id});
mark[es[i].id]=1;
sum++;
}
}
void Up(int &x,int c){
chkmin(res[tree[x].id],c);
x=tree[x].fa;
}
void work(int a,int b,int c){
while(D[a]>D[b])Up(a,c);
while(D[a]<D[b])Up(b,c);
while(a!=b)Up(a,c),Up(b,c);
}
void solve(){
sum=ans=0;
Kruskal();
if(sum<n-1){
REP(i,1,m)puts("-1");
exit(0);
}
dfs(1,0,0);
REP(i,1,m){
if(mark[es[i].id])continue;
work(es[i].from,es[i].to,es[i].cost);
}
REP(i,1,m){
if(!mark[i])printf("%d\n",ans);
else if(!res[i])puts("-1");
else printf("%d\n",ans+res[i]-es[Id[i]].cost);
}
}
}p100;
int main(){
scanf("%d%d",&n,&m);
REP(i,1,n)fa[i]=i;
REP(i,1,m)scanf("%d%d%d",&es[i].from,&es[i].to,&es[i].cost),es[i].id=i;
sort(es+1,es+1+m);
REP(i,1,m)Id[es[i].id]=i;
if(m<=3000)p50.solve();
else p100.solve();
// p100.solve();
return 0;
}
小结:由于这次第2题又犯了低级错误,而且还是考试最后几分钟改错的,可见最后5分钟还是解放双手,好好检查…