[2018百度之星决赛][T3/T4]

Choice is an illusion created between those with power and those without. 

                                                                                                                     《The Matrix》

炒鸡喜欢《The Matrix》,追几遍都超酷,深思极恐的乐趣,以及人类法则,规则本身,程序设计(最后这个是乱加的)的思考。

所以回到题目

T3

题目大意

度度熊有一张n个点m条边的**无向图**,第i个点的点权为vi。

如果图上存在一条**路径**使得点i可以走到点j,则称i,j是**带劲**的,记f(i,j)=1;否则f(i,j)=0。显然有f(i,j)=f(j,i)。

度度熊想知道求出:
∑i(1<=i<=n)∑j(i+1<=j<=n)  f(i,j)×max(vi,vj)×(vi&vj)

其中&是C++中的and位运算符,如1&3=1, 2&3=2。

请将答案对1e9+7取模后输出。

两个关键点

 首先判断无向图中两个点是否可以连通

两种方法:1、对点进行dfs  感觉较下一种写起来有点复杂

                 2、并查集维护(记录每个点在哪个集中即可,具体可看代码)(注意并查集只能针对无向图而言,不针对有向图)

小拓展:判断有向图中两个点是否可以连通

               tarjan  只适用于强连通(a能到b b也能到a)

               单连通 又是怎样的? 那就传递闭包吧(还没有找到更好的方法)

处理这个式子  针对max要高效处理 可以排序 

根据&二进制特性  dp处理比这个数小的数中的每一位0/1的数量个数 一位位考虑,统一加即可。

 

T4

题意:

度度熊有k(k≥2)个序列s1,s2,..,sk,每个序列的长度均为n,且序列中每个数均是1到n之间某个整数,请问这k个串有多少个长度大于0的**公共子序列**?

**解释**:在每个序列中都选出一些位置,并将这些位置对应的字符**顺次**拼接起来,当它们都相等时,称其为公共子序列。

答案可能很大,请对109+7取模。

就是求不同公共序列的个数(位置不同也算不同)

注意随机数据的特性,不会出现极端条件,

预处理状态(k行每行字母相同时位置序列),

然后判断状态与状态间是否可转移(及对于状态k行中每行的i的字母位置<j的),可转移时dp

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#include<vector>
using namespace std;
const long long mod=1e9+7;
long long t[100],x,y,n,m,T,x1,y11,ans,a[101005],root[101005],f[33];
vector <long long > w[101005];
int find(int x) {if (root[x]==x)  return x;else  return root[x]=find(root[x]);}
int main()
{  cin>>T;
   while (T--)
   { scanf("%lld%lld",&n,&m);
     for (int i=1;i<=n;i++)
      scanf("%lld",&a[i]),root[i]=i;
     for (int i=1;i<=m;i++)
     { scanf("%lld%lld",&x1,&y11);
       root[find(x1)]=find(y11);}  
       ans=0;
     for (int i=1;i<=n;i++)  w[i].clear();
     for (int i=1;i<=n;i++)
     {  w[find(i)].push_back(a[i]);}
     for (int i=1;i<=n;i++)
     {  if (w[i].size()>1)
        {    memset(f,0,sizeof(f));
            sort(w[i].begin(),w[i].end());
            for (int j=0;j<w[i].size();j++)
             {  long long w1=w[i][j];
                for (int l=0;l<=30;l++)
                if ((w1>>l)&1)
                {   ans=(ans+(f[l]*(1ll<<l))%mod*w1)%mod,f[l]++;}
              }
          }
        }
    cout<<ans<<endl;
   }
        
      
}
//自己代码找不到,贴一发和我写的类似的,感谢bestfy
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long
#define inf 1000000001
#define y1 y1___
using namespace std;
#define N 3005
#define mod 1000000007
int n,m,cnt,a[6][N],now[6],h[N][6],q[N],f[N],ans;vector<int> p[6][N];
void dfs(int x,int y){
	if (x>m){
		memcpy(h[++cnt],now,sizeof(now));
		return;
	}
	rep (i,0,(int)p[x][y].size()-1) now[x]=p[x][y][i],dfs(x+1,y);
}
bool cmp(int x,int y){return h[x][1]<h[y][1];}
bool smaller(int x,int y){rep (i,1,m) if (h[x][i]>=h[y][i]) return 0;return 1;}
int Main(){
	scanf("%d%d",&m,&n);
	rep (i,1,m){
		rep (j,1,n) p[i][j].clear();
		rep (j,1,n) scanf("%d",&a[i][j]),p[i][a[i][j]].push_back(j);
	}
	cnt=0;
	rep (i,1,n) dfs(1,i);
	rep (i,1,cnt) q[i]=i;
	sort(&q[1],&q[cnt+1],cmp);ans=0;
	rep (i,1,cnt){
		f[q[i]]=1;
		rep (j,1,i-1)
			if (smaller(q[j],q[i])) f[q[i]]=(f[q[i]]+f[q[j]])%mod;
		ans=(ans+f[q[i]])%mod;
	}
	printf("%d\n",ans);
	return 0;
}
int main(){
	int T;scanf("%d",&T);while (T--) Main();
	return 0;
}
//预处理+dp

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章