聯考20200805 T1
阿新 • • 發佈:2020-08-06
分析:
考場上寫一個最劣會被卡到\(O(n^2k!k)\)的做法,沒加任何剪枝只想撈50分,竟然過了??
最後兩個點936ms,感謝不殺之恩。。。
首先我們發現一個右端點對應的左端點單調不降,於是two pointer
中間的值我是暴力判斷是否合法的,正解在這裡有了優化
把排列的所有方案都表示出來,一共有326種狀態,在這些狀態之中進行轉移
複雜度\(O(nk!k)\)
寫起來太精汙了,直接上暴力(
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #define maxn 100005 using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,K; int a[maxn][5]; int L[maxn],P[maxn],vis[maxn]; long long ans; inline bool check(int l,int r) { int A[5],cnt=0; for(int i=l;i<=r;i++) { bool p=0; for(int j=0;j<cnt;j++)if(a[i][P[j]]==A[j]){p=1;break;} if(!p) { if(cnt==K)return 0; A[cnt]=a[i][P[cnt]],cnt++; } } return 1; } inline void solve() { int now=1; for(int i=1;i<=n;i++) { while(now<i&&!check(now,i))now++; L[i]=min(L[i],now); } } inline void dfs(int x) { if(x==K){solve();return;} for(int i=0;i<K;i++)if(!vis[i]) vis[i]=1,P[x]=i,dfs(x+1),vis[i]=0; } int main() { n=getint(),K=getint(); for(int i=1;i<=n;i++)for(int j=0;j<K;j++)a[i][j]=getint(); for(int i=1;i<=n;i++)L[i]=i; if(K==1) { for(int i=2;i<=n;i++)if(a[i][0]==a[i-1][0])L[i]=L[i-1]; for(int i=1;i<=n;i++)ans+=1ll*(i-L[i]+1)*(i-L[i]+2)/2; printf("%lld\n",ans); return 0; } dfs(0); for(int i=1;i<=n;i++)ans+=1ll*(i-L[i]+1)*(i-L[i]+2)/2; printf("%lld\n",ans); }