1139C,P2761 软件补丁,P2831 [NOIP2016 提高组]

98 阅读2分钟

1139C - Edgy Trees 并查集

一共有n的k次方个序列,我们可以发现被0边连起来的一些点是都不可以走的,所以可以算出每个被0边连起来的团体的siz,然后用总数减去就行,注意每个顶点可以成为一个序列这个看样例1就行,所以我们一开始的ans=n^k-n,之后如果再减去siz^k时这些顶点就被减去了2次,所以再加上siz

,还要注意并查集中siz数组合并时不是加1而是加上相应的siz,看代码就理解了

int main(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++) s[i]=i,val[i]=1,vis[i]=0;
    for(int i=1;i<n;i++){
        ll u,v,x;
        scanf("%lld%lld%lld",&u,&v,&x);
        if(x==0){
            uni(u,v);
        }
    }
    ll ans=(qpow(n,k)-n+mod)%mod;
    for(int i=1;i<=n;i++){
        ll x=findd(i);
        if(!vis[x]){
              //  cout<<val[x]<<" "<<x<<endl;
            ans=(ans-qpow(val[x],k)+val[x]+mod)%mod;
            vis[x]=1;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

P2761 软件补丁问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 状压加bfs

判断需要注意的点就是f1操作是把n中的错误给消掉,本以为用一个异或就可以了,但这是不对的,因为如果n中的这个位置是0,而f1中的这个位置是1的话就成了添加错误了,所以应该是先或一遍f1然后再异或f1,另外单纯的用状压只能得80分,原因还不大清楚,说是因为有环,,正解是用最短路,因为spfa写起来比较简便就用了(其实就是题解是spfa,懒得再去看dij),但其实这就是一个bfs,不同的点是遍历完一遍m后应该将vis[u]置0,因为有时候需要多次用到同一个补丁

题解 P2761 【软件补丁问题】 - FCBM71 的老巢 - 洛谷博客

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll n,m,dp[1100000],t[110];
struct node{
    ll b1,b2,f1,f2;
}a[110];
char ch[110];
ll vis[1100000];
void bfs(){
    queue<ll>q;
    q.push((1<<n)-1);
    while(!q.empty()){
        ll u=q.front();q.pop();
        for(int i=1;i<=m;i++){
            ll s=u;
            if((s&a[i].b1)==a[i].b1&&(s&a[i].b2)==0){
                s=(((u|a[i].f1)^a[i].f1)|a[i].f2);
                if(dp[s]>dp[u]+t[i]){
                    dp[s]=dp[u]+t[i];
                    if(!vis[s]) q.push(s),vis[s]=1;
                }
            }
        }
        vis[u]=0;
    }
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%lld",&t[i]);
        scanf("%s",ch+1);
        vis[i]=0;
        ll fac=1;
        for(int j=n;j>=1;j--){
            if(ch[j]=='+') a[i].b1+=fac;
            if(ch[j]=='-') a[i].b2+=fac;
            fac*=2;
        }
        fac=1;
        scanf("%s",ch+1);
        for(int j=n;j>=1;j--){
            if(ch[j]=='+') a[i].f2+=fac;
            if(ch[j]=='-') a[i].f1+=fac;
            fac*=2;
        }
    }
    for(int i=0;i<(1<<n);i++) dp[i]=1e18;
    dp[(1<<n)-1]=0;
    bfs();
    //spfa();
    if(dp[0]!=1e18) printf("%lld\n",dp[0]);
    else printf("0\n");
    return 0;
}

P2831 [NOIP2016 提高组] 愤怒的小鸟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

正解是状压,s中的1表示这位上得猪被打死,dp[s]表示s这个状态最少需要多少鸟,两两枚举猪求出所有的抛物线,然后再求出每个抛物线能干掉多少猪,之后再进行转移,但是有个优化没看懂,打完cf再来看这个优化和写代码,这时间也太不凑巧了,,,