题解:
我们先将我们的亮度从大到小排序,然后我们依次加入x点,并且加入和这个点相连的所有点,如果新加入的y点的亮度大于x点,那么我们就把他们合并。在之后我们计算答案的时候,对于x节点,当需要删除他的时候他已经减去了他的父亲节点的亮度了,所以只需要再减去剩下的 d − d f a t h e r d-d_{father} d−dfather的答案。所以最后求一下和就可以了。
#include
using namespace std;
typedef long long ll;
const int N=100010;
int d[N],f[N],fa[N],vis[N],num[N];
vector<int> g[N];
int cmp(int a,int b)
{
return d[a]>d[b];
}
int find(int x)
{
if(f[x]==x) return f[x];
return f[x]=find(f[x]);
}
signed main()
{
int t; scanf("%d",&t);
while(t--){
int n,m; scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<=n;i++) {
scanf("%d",&d[i]);
f[i]=i;
vis[i]=fa[i]=0;
num[i]=i;
}
sort(num+1,num+1+n,cmp);
for(int i=1;i<=m;i++) {
int a,b; scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
for(int i=1;i<=n;i++){
int x=num[i];
vis[x]=1;
for(auto it:g[x]){
if(!vis[it]) continue;
int fy=find(it);
if(fy==x) continue;
fa[fy]=f[fy]=x;
}
}
ll res=0;
for(int i=1;i<=n;i++) res+=d[i]-d[fa[i]];
printf("%lld\n",res);
}
}
题解:
双哈希过去。因为我们只是把一个1翻成了0,所以枚举C数组遇见0就把他翻转过来看是不是hash值相等,如果相等则答案就是这一位。
#include
#define int long long
using namespace std;
const int mod=1e9+9,mod1=1e9+7,N=2e6+10;
int f[N],f1[N],na,nb,nc,sa,sb,sc,sa1,sb1,sc1,a[N],b[N],c[N];
void solve(){
scanf("%lld",&na);
for(int i=1;i<=na;i++) scanf("%lld",&a[i]);
scanf("%lld",&nb);
for(int i=1;i<=nb;i++) scanf("%lld",&b[i]);
scanf("%lld",&nc);
for(int i=1;i<=nc;i++) scanf("%lld",&c[i]);
sa=sb=sc=0; sa1=sb1=sc1=0;
for(int i=1;i<=na;i++) sa=(sa+f[i]*a[i])%mod;
for(int i=1;i<=nb;i++) sb=(sb+f[i]*b[i])%mod;
for(int i=1;i<=nc;i++) sc=(sc+f[i]*c[i])%mod;
for(int i=1;i<=na;i++) sa1=(sa1+f1[i]*a[i])%mod1;
for(int i=1;i<=nb;i++) sb1=(sb1+f1[i]*b[i])%mod1;
for(int i=1;i<=nc;i++) sc1=(sc1+f1[i]*c[i])%mod1;
for(int i=1;i<=nc;i++) if(c[i]==0){
int tmp=(sc+f[i])%mod,tmp1=(sc1+f1[i])%mod1;
if(tmp==(sa*sb)%mod&&tmp1==(sa1*sb1)%mod1){
printf("%lld\n",i); break;
}
}
}
signed main(){
f[1]=1,f[2]=2;
for(int i=3;i<N;i++) f[i]=(f[i-1]+f[i-2])%mod;
f1[1]=1,f1[2]=2;
for(int i=3;i<N;i++) f1[i]=(f1[i-1]+f1[i-2])%mod1;
int T; cin>>T; while(T--) solve();
return 0;
}
题解:
直接爆搜,正向搜wa了,但是反向可以过,队友给我说的是机组原理的一些知识,但是我不会,呜呜呜。
#include
using namespace std;
typedef long long ll;
const int N=100;
int n,m;
int f[N][N][5],cnt[N];
ll res;
void dfs(int x,int a,int b,int c,int d)
{
if(x<1){
ll tmp=1LL*a*b*c*d;
res=max(res,tmp);
return;
}
if(!cnt[x]){
dfs(x-1,a,b,c,d);
return;
}
for(int i=1;i<=cnt[x];i++) dfs(x-1,f[x][i][1]+a,f[x][i][2]+b,f[x][i][3]+c,f[x][i][4]+d);
}
signed main()
{
int t; scanf("%d",&t);
while(t--){
res=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) cnt[i]=0;
for(int i=1;i<=n;i++){
int tmp; scanf("%d",&tmp);
cnt[tmp]++;
for(int j=1;j<=4;j++) scanf("%d",&f[tmp][cnt[tmp]][j]);
}
dfs(m,100,100,100,100);
printf("%lld\n",res);
}
}
题解:
序列自动机预处理出当前位置 i i i距离最近的字母 j j j的最近下标。
我们定义 f i , j f_{i,j} fi,j为B数组[1…i]这段字符串和A数组[l,r]这段字符串匹配到 L C S LCS LCS的长度为 j j j的时候所需要的A的数组最小下标 x x x, ( l < = x < = r ) (l<=x<=r) (l<=x<=r)也就是题解中的最小前缀和。dp函数方程式中当我们匹配的x的位置小于r的时候 n x t [ f [ i − 1 ] [ j − 1 ] + 1 ] [ b [ i ] − ′ a ′ ] nxt[f[i-1][j-1]+1][b[i]-'a'] nxt[f[i−1][j−1]+1][b[i]−′a′],需要 f [ i − 1 ] [ j − 1 ] + 1 f[i-1][j-1]+1 f[i−1][j−1]+1,因为我们当前位置也可能是这个字母,就会发生错误。最后我们反向循环找最长的 L C S LCS LCS因为我们答案是 l e n a + l e n b − 2 ∗ L C S lena+lenb-2*LCS lena+lenb−2∗LCS,所以需要保证 L C S LCS LCS最大。
#include
using namespace std;
const int N=1e5+10;
const int INF=0x3f3f3f3f;
int f[50][50];
char a[N],b[N];
struct sub_AM{
int nxt[N][30];
void init(){
int l=strlen(a+1);
for(int i=0;i<26;i++) nxt[l][i]=l+1;
nxt[l][a[l]-'a']=l;
for(int i=l-1;i>=1;i--){
for(int j=0;j<26;j++){
nxt[i][j]=nxt[i+1][j];
}
nxt[i][a[i]-'a']=i;
}
}
// bool find(char *t){
// int pos=-1;
// int l=strlen(t);
// for(int i=0;i
// pos=nxt[pos+1][t[i]-'a'];
// if(pos==INF) return 0;
// }
// return 1;
// }
}solve;
signed main()
{
int t; scanf("%d",&t);
while(t--){
scanf("%s",a+1);
scanf("%s",b+1);
int lenb=strlen(b+1);
solve.init();
int q; scanf("%d",&q);
while(q--) {
int l, r;
scanf("%d%d", &l, &r);
memset(f,INF,sizeof f);
// f[0][0]=l-1;
// for(int i=1;i<=lenb;i++) f[i][0]=nxt[l][b[i]-'a']-1;
for(int i=1;i<=lenb;i++) f[i][1]=solve.nxt[l][b[i]-'a'];
for (int i = 1; i <= lenb; i++) {
for (int j = 1; j <= i; j++) {
if(f[i-1][j]<=r) f[i][j]=min(f[i][j],f[i-1][j]);
if(f[i-1][j-1]<r) f[i][j]=min(f[i][j],solve.nxt[f[i-1][j-1]+1][b[i]-'a']);
}
}
int tmp=0;
for(int i=lenb;i>0;i--){
if(f[lenb][i]<=r) {
tmp=i;
break;
}
}
// cout<<"tmp : "<
int res=(r-l+1+lenb)-2*tmp;
printf("%d\n",res);
}
}
}