考崩了。。。没有一道AC。。
写书 2979
只有10分。。。
有一个10敲成9了 对拍两个小时 。。。
这种题目下次对拍造数据可以不随机 直接从1循环到n
LR棋盘 2980
鼓捣一个多小时 想用组合数写 最后只能把LR切开打暴力 只有40
考完发现其实是DP
其实跟上次欢乐赛的第二题挺像的 上次秒A,这次居然没看出来。。。
由题意知道 棋子之间的相对位置是不变的
那么就可以DP了
定义dp[i]为以第i个棋子结尾的方案数
预处理每个棋子能到达的位置
再枚举棋盘上的位置 循环棋子 并判断能否到达 更新dp数组
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)
#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)
#define INF 0x3f3f3f3f
#define LL long long
#define M 100005
#define P 1000000007
#define T 6000007
char str[M];
struct node{
int L,R;
}A[M];
LL dp[M];
int n,m;
void Insert(int s){
if(str[s]=='.') return ;
++m;
if(str[s]=='L')A[m].L=1,A[m].R=s;
if(str[s]=='R')A[m].L=s,A[m].R=n;
}
int main() {
scanf("%s",str+1);
n=strlen(str+1);
FOR(i,1,n) Insert(i);
dp[0]=1;
FOR(i,1,n)DOR(j,m,1)
if(i>=A[j].L&&i<=A[j].R)
dp[j]=(dp[j]+dp[j-1])%P;
printf("%lld\n",dp[m]);
return 0;
}
道路评价 2981
当时就直接n*n打了个暴力 有60分 反而这题得分最高。。。
想到枚举每条边 判两边数量 再更新ans 但如果直接暴力求数量 还是要n*n的复杂度
主要是并查集还不怎么6
正解就是通过并查集来压缩路径
当然直接循环的话 就可能把没用到的边给压没掉
可以分开求maxl和minl
首先每个集合数量为1 也就是它本身
当求某一条两边的合法数量时
如果某一个集合的最优解并不如当前线段
那么这个集合就可以直接并入整个集合
如果可以保证当前边始终由于当前树中的连边 就可以直接压缩已经更新的路径了
那么sort一下就好了
如果求minl就将所有边按权值从大到小排序 就可以保证最优了
且当前不存在的连边就不需要继续向下找
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)
#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)
#define INF 0x3f3f3f3f
#define LL long long
#define M 100005
inline void chkmi(int &a,int b){if(a>b)a=b;}
inline void chkmx(int &a,int b){if(a<b)a=b;}
inline int MIN(int a,int b){if(a<b)return a;return b;}
inline int MAX(int a,int b){if(a>b)return a;return b;}
struct node{int to,v;};
struct edge{
int fr,to,v;
bool operator <(const edge &a)const{
return v>a.v;
}
}A[M];
int mark[M],Fa[M],cnt[M];
int n;
LL maxl,minl;
int Find(int x){return Fa[x]==x?x:Fa[x]=Find(Fa[x]);}
void Init(){FOR(i,1,n) Fa[i]=i,cnt[i]=1;}
int main(){
cin>>n;
FOR(i,2,n)scanf("%d%d%d",&A[i].fr,&A[i].to,&A[i].v);
sort(A+1,A+n+1);
Init();
FOR(i,1,n-1){
int a=Find(A[i].fr);
int b=Find(A[i].to);
Fa[a]=b;
minl+=1ll*A[i].v*cnt[a]*cnt[b];
cnt[b]+=cnt[a];
}
Init();
DOR(i,n-1,1){
int a=Find(A[i].fr);
int b=Find(A[i].to);
Fa[a]=b;
maxl+=1ll*A[i].v*cnt[a]*cnt[b];
cnt[b]+=cnt[a];
}
cout<<maxl-minl<<endl;
return 0;
}