[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

 

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