「10.21-10.22」day1-day2

我好像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 
*/
View Code

$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 */
View Code

$T3$

乱搞不会

$day2$


T1

猜你喜欢

转载自www.cnblogs.com/Wwb123/p/11737250.html