我好像gugu很久了
$day1$
$T1$
一道大神状压DP题
事实上不会时间复杂度证明,只是打完后发现极限数据跑的很快,然后就A了
$f_{ijs}$表示当前处理第$i$列,然后当前点亮的状态为$s$,然后$j$为按钮状态
然后就可以转移了
/* f[i][j][k]第i列,灯泡状态,当前点亮状态, */ #include<bits/stdc++.h> #define MAXN 25 using namespace std; int f[12][(1<<10)+1][(1<<10)+1]; int a[MAXN][MAXN]; int n,m; int val[MAXN][MAXN]; vector<int>v[MAXN*100]; int read(){ char c=getchar();int x=0;int ff=1; while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*ff; } char lo[MAXN][MAXN]; int kx[MAXN];//原列已点亮状态 int belong[MAXN*100];//灯泡状态下的点亮状态 int sum[MAXN][MAXN*100];//灯泡状态下的花费 signed main(){ //freopen("t1.in","r",stdin); //freopen("matrix.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;++i){ scanf("%s",lo[i]+1); for(int j=1;j<=m;++j){ if(lo[i][j]=='1')a[i][j]=1;else a[i][j]=0; } } for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ val[i][j]=read(); } } for(int j=1;j<=m;++j){ for(int i=1;i<=n;++i){ if(a[i][j])kx[j]|=(1<<(i-1)); } } for(int i=0;i<(1<<n);++i){ for(int j=0;j<=i;++j){ if((i&j)==j||(i==j)){ v[j].push_back(i); //printf("j=%d i=%d\n",j,i); } } } for(int i=0;i<(1<<n);++i){ int me=i; for(int j=0;j<n;++j){ if(!((i>>j)&1))continue; if(j-1>=0)me|=(1<<(j-1)); if(j+1<n)me|=(1<<(j+1)); } belong[i]=me; //printf("belong[%d]=%d\n",i,me); } for(int j=1;j<=m;++j){ for(int i=0;i<(1<<n);++i){ int summ=0; for(int k=0;k<n;++k){ if((i>>k)&1)summ+=val[k+1][j]; } sum[j][i]=summ; //printf("sum[%d][%d]=%d\n",j,i,sum[j][i]); } } memset(f,0x3f3f3f,sizeof(f)); for(int i=0;i<(1<<n);++i){ f[1][i][belong[i]|kx[1]]=sum[1][i]; //printf("f[%d][%d][%d]=%d\n",1,i,belong[i]|kx[1],sum[1][i]); } for(int j=2;j<=m;++j){ for(int i=0;i<(1<<n);++i){ for(int k=0;k<(1<<n);++k){ for(int w=0;w<v[belong[k]|kx[j-1]].size();++w){ int to=v[belong[k]|kx[j-1]][w];//printf("i=%d k=%d to=%d\n",i,k,to); if((to|i)!=(1<<n)-1)continue; f[j][i][belong[i]|k|kx[j]]=min(f[j][i][belong[i]|k|kx[j]],f[j-1][k][to]+sum[j][i]); } } } } int minn=0x7fffffff; for(int i=0;i<(1<<n);++i){ minn=min(f[m][i][(1<<n)-1],minn); } printf("%d\n",minn); } /* 3 2 01 00 10 38 3 32 27 34 31 */
$T2$
一道很吃*的题
%%%kx考场90分
将思路转化,考虑先以$val$排序,然后我们考虑在序列里插数
在插数中发现以前插的数的顺序与当前数无关
找最小序列的话,我们要保证在插数时找到当前序列的中第一个比他$key$值大的数
然后插在他的前面,注意特判
90分链表即可,100分就需要线段树或平衡树
1 #include<bits/stdc++.h> 2 #define MAXN 550100 3 using namespace std; 4 const int mod=1e9+7; 5 struct node{int val,id,key;}e[MAXN]; 6 int n; 7 int read(){ 8 char c=getchar();int x=0;int ff=1; 9 while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();} 10 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} 11 return x*ff; 12 } 13 long long ans=1;int nxt[MAXN],pre[MAXN];int me[MAXN]; 14 bool cmp(node a,node b){ 15 return (a.val==b.val)?(a.key<b.key):(a.val>b.val); 16 } 17 signed main(){ 18 n=read(); 19 for(int i=1;i<=n;++i){ 20 e[i].id=i; 21 e[i].key=read(); 22 e[i].val=read(); 23 } 24 int add=0; 25 sort(e+1,e+n+1,cmp); 26 for(int i=1;i<=n;++i){ 27 if(e[i].val==e[i-1].val&&i!=1)add++; 28 else add=0; 29 ans=1ll*ans*min(i,e[i].key+add)%mod; 30 } 31 printf("%lld\n",ans%mod); 32 int pos_pre=1; 33 nxt[1]=n+1;pre[n+1]=1; 34 e[n+1].key=0x7fffffff; 35 for(int i=2;i<=n;++i){ 36 if(e[i].val==e[i-1].val)add++;else add=0; 37 int now=0;int sum=0; 38 for(int j=pos_pre;j;j=nxt[j]){ 39 if(e[j].key>=e[i].key){now=j;break;} 40 sum++; 41 if(sum>=min(e[i].key+add,i)){now=j;break;} 42 } 43 if(now==pos_pre){ 44 nxt[i]=pos_pre; 45 pre[pos_pre]=i; 46 pos_pre=i; 47 } 48 else{ 49 int y=pre[now]; 50 pre[now]=i;nxt[i]=now; 51 nxt[y]=i;pre[i]=y; 52 } 53 } 54 for(int i=pos_pre;i;i=nxt[i]){ 55 me[++me[0]]=i; 56 } 57 for(int i=1;i<=me[0]-1;++i){ 58 printf("%d %d\n",e[me[i]].key,e[me[i]].val); 59 } 60 } 61 /* 62 4 63 4 1 64 2 3 65 2 2 66 5 4 67 */
$T3$
乱搞不会
$day2$
T1