BestCoder Round #74 (div.2)

来源:互联网 发布:淘宝上卖自己做的熟食 编辑:程序博客网 时间:2024/06/04 18:05

未完待续~~
划分等价类,判断是否无解,26*25^(m-1)即可,倒着来~
​​

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>using namespace std;#define N 100010#define Mod 1000000007LLint n;int A[N];long long Dp[N];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int main(){    int T=read();    while(T--)    {        n=read();        memset(Dp,0,sizeof(Dp));        memset(A,0,sizeof(A));        Dp[n]=26;        for(int i=1;i<=n-1;i++)            A[i]=read();        for(int i=n-1;i>=1;i--)        {            if(A[i]==0)                Dp[i]=Dp[i+1]*25%Mod;            else if(A[i]==A[i+1]+1)                Dp[i]=Dp[i+1];            else            {                Dp[i]=0;                break;            }        }        printf("%I64d\n",Dp[1]);    }    return 0;}

直接对新的点建图,然后flyod,最后算答案的是后6*6,枚举转折点更新答案即可!

#include<bits/stdc++.h>using namespace std;#define ll long longconst int maxn=1e5+10;int a[10],dis[10][10],n,m;const ll mod=1e9+7;int main(){    int t;cin>>t;    while(t--){        scanf("%d%d",&n,&m);        for(int i=1;i<=6;i++){            scanf("%d",&a[i]);        }        for(int i=1;i<=6;i++){            for(int j=1;j<=6;j++){                dis[i][j]=abs(a[i]-a[j]);            }        }        for(int i=1;i<=5;i+=2){            dis[i][i+1]=dis[i+1][i]=1;        }        for(int k=1;k<=6;k++){            for(int i=1;i<=6;i++){                for(int j=1;j<=6;j++){                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);                }            }        }        int s,t;ll anss=0;        for(ll k=1;k<=m;k++){            scanf("%d%d",&s,&t);            ll ans=abs(s-t);            for(int i=1;i<=6;i++){                for(int j=1;j<=6;j++){                    ans=min(ans,(ll)(abs(s-a[i])+abs(t-a[j])+dis[i][j]));                }            }            anss=(anss+k*ans)%mod;        }        printf("%lld\n",anss);    }}

利用异或性质进行bfs,O(1)查询!

#include<bits/stdc++.h>using namespace std;#define ll long longconst ll mod=1e9+7;const int maxn=1e6+10;int dis[maxn],vis[maxn];int n,m,a[20],s,t;void bfs(){    queue<int>q;    while(!q.empty())q.pop();    q.push(0);dis[0]=0;vis[0]=1;    while(!q.empty()){        int now=q.front();q.pop();        for(int i=0;i<17;i++){            if(vis[(1<<i)^now]) continue;            dis[(1<<i)^now]=dis[now]+1;q.push((1<<i)^now);            vis[(1<<i)^now]=1;        }        for(int i=1;i<=n;i++){            if(vis[a[i]^now]) continue;            dis[a[i]^now]=dis[now]+1;q.push(a[i]^now);            vis[a[i]^now]=1;        }    }}int main(){    //cout<<"== "<<(1<<15)<<endl;    int tt;cin>>tt;    while(tt--){        ll anss=0;        scanf("%d%d",&n,&m);memset(dis,0x7f7f7f7f,sizeof(dis));        memset(vis,0,sizeof(vis));        for(int i=1;i<=n;i++){scanf("%d",&a[i]);}        bfs();        for(ll i=1;i<=m;i++){            scanf("%d%d",&s,&t);            anss=(anss+i*dis[s^t])%mod;        }        printf("%lld\n",anss);    }}

题意:求删除恰好k条边后,能够使得字典序最小的拓扑序列~
题解:参考下普通的用堆维护求字典序最小拓扑序, 用某种数据结构维护入度小于等于kk的所有点, 每次找出编号最小的, 并相应的减少k即可.

这个数据结构可以用线段树, 建立一个线段树每个节点[l,r][l,r]维护编号从ll到rr的所有节点的最小入度, 查询的时候只需要在线段树上二分, 找到最小的xx满足入度小于等于k.

这个结构也可用优先队列,每次把入度小于等于k的入队,弹出序号最小的标号,把它作为拓扑的下一个,代价就是把它的入度全部用k删掉,然后把这个点以及它连的边都删掉,再更新入队的元素就可以了~

#include<bits/stdc++.h>#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))#if defined(_MSC_VER) || __cplusplus > 199711L#define aut(r,v) auto r = (v)#else#define aut(r,v) __typeof(v) r = (v)#endif#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)#define all(o) (o).begin(), (o).end()#define pb(x) push_back(x)#define mp(x,y) make_pair((x),(y))#define mset(m,v) memset(m,v,sizeof(m))#define INF 0x3f3f3f3f#define INFL 0x3f3f3f3f3f3f3f3fLLusing namespace std;typedef vector<int> vi; typedef pair<int, int> pii; typedef vector<pair<int, int> > vpii; typedef long long ll;template<typename T, typename U> inline void amin(T &x, U y) { if(y < x) x = y; }template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }int main() {    int T;    scanf("%d", &T);    for(int ii = 0; ii < T; ++ ii) {        int n; int m; int k;        scanf("%d%d%d", &n, &m, &k);        vector<vector<int> > g(n);        vi deg(n);        for(int i = 0; i < m; ++ i) {            int u, v;            scanf("%d%d", &u, &v), -- u, -- v;            g[u].push_back(v);            ++ deg[v];        }        priority_queue<int,vi,greater<int> > q;        rep(i, n) if(deg[i] <= k)            q.push(i);        vector<bool> used(n, false);        ll anssum = 0;        rep(t, n) {            int i;            while(1) {                i = q.top(); q.pop();                if(!used[i] && deg[i] <= k)                    break;            }           // cout<<"i= "<<i<<endl;            anssum += (ll)(t + 1) * (i + 1);            k -= deg[i];            used[i] = true;            each(j, g[i]) if(!used[*j]) {                if(-- deg[*j] <= k)                    q.push(*j);            }        }        printf("%d\n", (int)(anssum % 1000000007));    }    return 0;}

线段树不过就是换一种数据结构来维护罢了,方法都是一样的~

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int N=100010;const int mo=1e9+7;struct bian{    int next,point;}b[410000];int num[N<<2],d[N],n,m,p[N],K,len,where,w;void add(int k1,int k2){    d[k2]++; b[++len]=(bian){p[k1],k2}; p[k1]=len;}void buildtree(int k1,int k2,int k3){    if (k2==k3){        num[k1]=d[k2]; return;    }    int mid=k2+k3>>1;    buildtree(k1*2,k2,mid); buildtree(k1*2+1,mid+1,k3);    num[k1]=min(num[k1*2],num[k1*2+1]);}int find(int k1,int k2,int k3){//    cout<<"fa "<<k1<<" "<<num[k1]<<" "<<num[k1*2]<<" "<<k2<<" "<<k3<<" "<<K<<endl;    if (k2==k3) return k2;    int mid=k2+k3>>1;    if (num[k1*2]<=K)        return find(k1*2,k2,mid);    else return find(k1*2+1,mid+1,k3);}void change(int k1,int k2,int k3){    if (k2==k3){        num[k1]=d[where]; return;    }    int mid=k2+k3>>1;    if (mid>=where) change(k1*2,k2,mid); else change(k1*2+1,mid+1,k3);    num[k1]=min(num[k1*2],num[k1*2+1]);}void solve(){    scanf("%d%d%d",&n,&m,&K); len=0;    for (int i=1;i<=n;i++) p[i]=0,d[i]=0;    for (int i=1;i<=m;i++){        int k1,k2; scanf("%d%d",&k1,&k2); add(k1,k2);    }    buildtree(1,1,n); int ans=0;    for (int t=1;t<=n;t++){        int now=find(1,1,n); ans=(ans+1ll*t*now)%mo;    //    cout<<"faaa "<<now<<" "<<d[now]<<" "<<K<<endl;        K-=d[now];        for (int i=p[now];i;i=b[i].next){            int j=b[i].point;            d[j]--; where=j; change(1,1,n);        }        where=now; d[now]=1e9; change(1,1,n);    }    printf("%d\n",ans);}int main(){    int t; scanf("%d",&t);    for (;t;t--) solve();    return 0;}
0 0
原创粉丝点击