标签:work main 字符串 最短路 bit tmp 直接 mes void
可以推一发公式。设f(x)表示n=x时的方案数。当新加入一个元素时,有如下两种情况:
1、与新加入的元素相邻的两个元素颜色不同,方案数就是f(x-1)*(m-2)。
2、与新加入的元素相邻的两个元素颜色相同,方案数就是f(x-2)*(m-1)。
(也就是直接插入两个元素,一个颜色有(m-1)种,另一个为满足该条件就只有一种颜色可行)
因此,得到f(x)=(m-2)*f(x-1)+(m-1)*f(x-2)。
再用矩阵快速幂优化就行了。(还要加特判)
时间复杂度O(logn*2^3)。
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int MOD=998244353; 5 //f(n)=f(n-1)*(m-2)+f(n-2)*(m-1) 6 struct Martix{ 7 int mar[3][3]; 8 Martix operator * (const Martix& x)const{ 9 Martix res; 10 memset(res.mar,0,sizeof(res.mar)); 11 for(int i=1;i<=2;i++) 12 for(int j=1;j<=2;j++) 13 for(int k=1;k<=2;k++) 14 { 15 (res.mar[i][j]+=mar[i][k]*x.mar[k][j])%=MOD; 16 } 17 return res; 18 } 19 }base,st,tmp; 20 Martix power(Martix a,int b) 21 { 22 if(b==0) return base; 23 Martix t=power(a,b>>1); 24 t=t*t; 25 if(b&1) t=t*a; 26 return t; 27 } 28 signed main() 29 { 30 int n,m; 31 scanf("%lld%lld",&n,&m); 32 if(m==1&&n!=1) return 0*printf("%lld\n",0ll); 33 tmp.mar[1][1]=m*(m-1)%MOD*(m-2)%MOD; 34 tmp.mar[1][2]=tmp.mar[2][1]=m*(m-1)%MOD; 35 tmp.mar[2][2]=m; 36 if(n==1) return 0*printf("%lld\n",m); 37 if(n==2) return 0*printf("%lld\n",m*(m-1)%MOD); 38 if(n==3) return 0*printf("%lld\n",m*(m-1)%MOD*(m-2)%MOD); 39 for(int i=1;i<=2;i++) base.mar[i][i]=1; 40 st.mar[1][1]=m-2;st.mar[2][1]=(m-1);st.mar[1][2]=1; 41 printf("%lld\n",(tmp*power(st,n-3)).mar[1][1]); 42 return 0; 43 }
首先,01矩阵显然可以转化为01串。(就当这是对第一题的温馨暗示吧)
然后,我就不会了。
以下是某大佬的解法:
对于任意一对01串,其中有若干位是不同的,那么选取这些位中的任意一个就使这对字符串得到区分。
于是这几位对这对01串的区分是有贡献的,就在他们的贡献中加入这一对字符串。(具体用状态压缩实现)
于是我们得到每一位的贡献。
对于每一对01串,我们都是需要区分的,因此假设我们选择了若干位来区分这些01串,那么这几位的贡献值按位或的结果必须是 (1<<C(k,2))-1,即每一位都是1。
于是这就成了选取最少的数使它们按位或的结果为给定的数。因为数据极小,直接dp就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=110,PO=(1<<15)+10,K=10; 4 int dp[N][PO],n,m,k,l,tot; 5 int a[K][N],b[N]; 6 void init() 7 { 8 memset(b,0,sizeof(b)); 9 char tmp; 10 scanf("%d%d%d",&n,&m,&k); 11 l=n*m; 12 for(int i=1;i<=k;i++) 13 { 14 for(int j=1;j<=l;j++) 15 { 16 tmp=getchar(); 17 while(tmp!=‘1‘&&tmp!=‘0‘) tmp=getchar(); 18 a[i][j]=tmp-‘0‘; 19 } 20 } 21 int num=1; 22 for(int i=1;i<=k;i++) 23 for(int j=i+1;j<=k;j++) 24 { 25 for(int pos=1;pos<=l;pos++) 26 if(a[i][pos]!=a[j][pos]) 27 b[pos]|=1<<num>>1; 28 num++; 29 } 30 num--; 31 tot=1<<num; 32 } 33 int main() 34 { 35 int t; 36 scanf("%d",&t); 37 while(t--) 38 { 39 init(); 40 memset(dp,0x3f,sizeof(dp)); 41 dp[0][0]=0; 42 for(int i=1;i<=l;i++) 43 for(int j=0;j<tot;j++) 44 { 45 if(dp[i][j|b[i]]>dp[i-1][j]+1) 46 dp[i][j|b[i]]=dp[i-1][j]+1; 47 if(dp[i][j]>dp[i-1][j]) 48 dp[i][j]=dp[i-1][j]; 49 } 50 printf("%d\n",dp[l][tot-1]); 51 } 52 return 0; 53 }
关键路径,两遍最短路的事。对于关键路径上的每一条边(u,v),把从dis[u]到dis[u]之间的点的答案加一就可以了。
然而我实现写萎了。实际上一个个点差分,再按距离顺序一个个点求和就可以了。
1 #include<bits/stdc++.h> 2 #define Pii pair<int,int> 3 #define INF 1<<30 4 using namespace std; 5 const int N=2010,M=200010; 6 struct edge{ 7 int la,b,v; 8 }con[M<<1]; 9 int fir[N],tot; 10 void add(int from,int to,int val) 11 { 12 con[++tot].la=fir[from]; 13 con[tot].b=to; 14 con[tot].v=val; 15 fir[from]=tot; 16 } 17 int n,s,t,m; 18 vector<int>fa[N]; 19 bool vis[N]; 20 int inq[N],diss[N],dist[N]; 21 struct cmp{ 22 bool operator () (const Pii &x,const Pii &y) 23 { 24 return x.second>y.second; 25 } 26 }; 27 priority_queue<Pii,vector<Pii>,cmp>q; 28 void dijkstra(int st,int *dis) 29 { 30 while(!q.empty()) q.pop(); 31 for(int i=1;i<=n;i++) dis[i]=INF; 32 dis[st]=0; 33 q.push(make_pair(st,dis[st])); 34 inq[st]=1; 35 int pos; 36 while(!q.empty()) 37 { 38 pos=q.top().first; 39 q.pop(); 40 if(--inq[pos]>0) continue; 41 for(int i=fir[pos];i;i=con[i].la) 42 { 43 if(dis[con[i].b]>dis[pos]+con[i].v) 44 { 45 dis[con[i].b]=dis[pos]+con[i].v; 46 q.push(make_pair(con[i].b,dis[con[i].b])); 47 inq[con[i].b]++; 48 } 49 } 50 } 51 } 52 struct value{ 53 int pos,val,num; 54 bool operator < (const value& x)const{ 55 if(pos!=x.pos) return pos<x.pos; 56 else return val<x.val; 57 } 58 }avail[N*3]; 59 int cnt,ans[N]; 60 void work() 61 { 62 int ru,chu,tmp=0; 63 for(int i=1;i<=n;i++) if(diss[i]+dist[i]==diss[t]) vis[i]=1; 64 for(int i=1;i<=n;i++) if(vis[i]) 65 { 66 ru=chu=-1; 67 for(int j=fir[i];j;j=con[j].la) if(vis[con[j].b]) 68 { 69 if(diss[con[j].b]+con[j].v==diss[i]) ru++; 70 if(diss[i]+con[j].v==diss[con[j].b]) chu++; 71 } 72 avail[++cnt]=(value){diss[i],ru*(-1),0}; 73 avail[++cnt]=(value){diss[i],0,i}; 74 avail[++cnt]=(value){diss[i],chu*1,0}; 75 } 76 sort(avail+1,avail+cnt+1); 77 for(int i=1;i<=cnt;i++) 78 { 79 if(avail[i].val==0) ans[avail[i].num]=tmp; 80 else tmp+=avail[i].val; 81 } 82 ans[s]=1;ans[t]=1; 83 } 84 int main() 85 { 86 int from,to,val; 87 scanf("%d%d%d%d",&n,&s,&t,&m); 88 for(int i=1;i<=m;i++) 89 { 90 scanf("%d%d%d",&from,&to,&val); 91 add(from,to,val); 92 add(to,from,val); 93 } 94 dijkstra(s,diss); 95 dijkstra(t,dist); 96 work(); 97 for(int i=1;i<=n;i++) printf("%d ",ans[i]); 98 printf("\n"); 99 return 0; 100 }
小结:今天题目确实偏简单。要积极给每道题写解法,以及在实现想法时不要不经考虑乱写。
标签:work main 字符串 最短路 bit tmp 直接 mes void
原文地址:http://www.cnblogs.com/cly-none/p/7642210.html