D1 - Xor-Subsequence (easy version),441C - Valera and Tubes,1234D

91 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 9 天,点击查看活动详情

D1 - Xor-Subsequence (easy version) dp

没能及时得看出规律来,淦,,

看到a只有200,可以发现异或这个操作只对二进制得后七位产生作用,所以我就像如果j<255,i>255的话i和j就不用比较了,一定是i大;但是却没想到其实对所有的i,j都是满足这个条件的,i只有和大于等于i-256的j比较才管用,因为别的再怎么异或都无济于事,所以第二层循环只要枚举i-300到i-1就可以了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll t,n,dp[400005],a[400005];
int main(){
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        for(int i=0;i<n;i++) scanf("%lld",&a[i]);
        for(int i=0;i<=n+10;i++) dp[i]=1;
        ll maxx=1;
        for(ll i=0;i<n;i++)
            for(ll j=max(0LL,i-300);j<i;j++){
                if((a[j]^i)<(a[i]^j)) dp[i]=max(dp[i],dp[j]+1);
                maxx=max(maxx,dp[i]);
            }
            printf("%lld\n",maxx);
    }
    return 0;
}

441C - Valera and Tubes

模拟矩阵螺旋构造,难的不在于思路而在于代码,思路无非就是每次都构造n*m/k个,最后一个把剩下的格子都按顺序输出就行

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll n,m,k,a[305][305];
int main(){
    scanf("%lld%lld%lld",&n,&m,&k);
    ll x=1,y=1,z=n*m/k,cnt=n*m,xn=1,ym=1,flag=0,zz;
    for(int i=1;i<=k;i++){
        if(i!=k) printf("%lld ",z),zz=z;
        else printf("%lld ",cnt),zz=cnt;
        while(zz--){
            printf("%lld %lld ",x,y);
            if(flag==0){
                y++;

                if(y>m){
                    y--;x++;flag=1;
                    xn++;
                }
            }
            else if(flag==1){
                x++;

                if(x>n){
                    x--;y--;flag=2;
                    m--;
                }
            }
            else if(flag==2){
                y--;
                if(y<ym){
                    y++;x--;flag=3;
                    n--;
                }
            }
            else if(flag==3){
                x--;
                if(x<xn){
                    x++;y++;flag=0;
                    ym++;
                }
            }
            cnt--;
        }
        printf("\n");
    }
    return 0;
}

1234D - Distinct Characters Queries 树状数组

可以发现字符串中只有字母,那么我们就直接开26个树状数组然后进行操作就可以,1操作我们就将原来字母的树状数组的这个位置-1,替换字母的树状数组的这个位置+1,同时把字符串数组更新;2操作直接遍历每个字符数组都查询一遍,如果不为0说明这个区间有这个字母,ans++

#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) (i)&(-i)
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll q,n,t[30][100005];
char s[100005];
void add(ll x,ll y,ll j){
    for(int i=x;i<=n;i+=lowbit(i))
        t[j][i]+=y;
}
ll ask(ll x,ll j){
    ll res=0;
    for(int i=x;i;i-=lowbit(i))
        res+=t[j][i];
    return res;
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++){
        add(i,1,s[i]-'a'+1);
    }
    scanf("%lld",&q);
    while(q--){
        ll op,x,y;
        char re[2];
        scanf("%lld%lld",&op,&x);
        if(op==1){
            scanf("%s",re);
            add(x,-1,s[x]-'a'+1);
            add(x,1,re[0]-'a'+1);
            s[x]=re[0];
        }
        else{
            scanf("%lld",&y);
            ll ans=0;
            for(int i=1;i<=26;i++){
                if(ask(y,i)-ask(x-1,i)>0) ans++;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

P2831 [NOIP2016 提高组] 愤怒的小鸟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 状压dp

昨天没来得及写代码的那个题,之所以可以按第一个没打的猪的坐标来遍历n个猪是因为这样是可以做到不漏的,这样遍历也是可以做到把每条抛物线都遍历到,因为一共2^n个状态,每个猪都可能是第一个没被打中的,所以这样就可以让复杂度少一个n,就可以顺利过掉该题了

题解 P2831 【愤怒的小鸟】 - Deep_Dark_Boy 的博客 - 洛谷博客

#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) (i)&(-i)
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
const double eps=1e-8;
ll t,n,m,dp[1100000],start[1100000],line[20][20];
double x[20],y[20];
void cal(double &a,double &b,ll i,ll j){
    a=-(y[i]*x[j]-y[j]*x[i])/(x[j]*x[j]*x[i]-x[i]*x[i]*x[j]);
    b=(y[i]*x[j]*x[j]-y[j]*x[i]*x[i])/(x[i]*x[j]*x[j]-x[j]*x[i]*x[i]);
}
int main(){
    scanf("%lld",&t);
    for(int i=0;i<(1<<18);i++){
        int j=1;
        while(j<=18&&i&(1<<(j-1))) j++;
        start[i]=j;
    }
    while(t--){
        scanf("%lld%lld",&n,&m);
        for(int i=0;i<(1<<n);i++) dp[i]=1e18;
        memset(line,0,sizeof(line));
        dp[0]=0;
        for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(fabs(x[i]-x[j])<eps) continue;
            double a,b;
            cal(a,b,i,j);
            if(a>-eps) continue;
            for(int k=1;k<=n;k++)
                if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<=eps) line[i][j]|=(1<<k-1);
        }
        for(int s=0;s<(1<<n);s++){
        ll j=start[s];
        dp[s|(1<<(j-1))]=min(dp[s|(1<<(j-1))],dp[s]+1);
        for(int i=1;i<=n;i++){
            dp[s|line[j][i]]=min(dp[s|line[j][i]],dp[s]+1);
        }
        }
        printf("%lld\n",dp[(1<<n)-1]);
    }

    return 0;
}

P2915 [USACO08NOV]Mixed Up Cows G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 状压dp

统计方案数是要dp[s|(1<<j-1)][j]+=dp[s][i];而不是+1,,,

其他的就是一个经典的排队问题,只需要判断一下差的绝对值是否是小于k的就行了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
const ll mod=1e9+7;
ll n,k,dp[100005][20],a[20];
int main(){
    scanf("%lld%lld",&n,&k);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]),dp[1<<(i-1)][i]=1;
    for(ll s=0;s<(1<<n);s++)
        for(ll i=1;i<=n;i++){
            //if(!(s&(1<<(i-1)))) continue;
            for(ll j=1;j<=n;j++){
        if(i==j) continue;
        if(abs(a[j]-a[i])<=k||s&(1<<j-1)) continue;
        dp[s|(1<<j-1)][j]+=dp[s][i];
    }
        }
    ll ans=0;
    for(ll i=1;i<=n;i++) ans+=dp[(1<<n)-1][i];
    printf("%lld\n",ans);
    return 0;
}

F-至至子的公司排队_牛客小白月赛55 (nowcoder.com) 树形dp 可重集排列

这个题最大的收获还是知道可重集排列是怎么算了吧,假设有集合{1,2,2,3,3,3,4,4,4,4},则他们的排列为\frac{10!}{1!2!3!4!}​编辑,之后这个题就是按这个公式去求就行了,最后求n家公司的排列也是一个可重集排列,另外在求每一家公司的时候dp[u]=\prod dp[son[u]]​可重集排列

F_哔哩哔哩_bilibili

#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) (i)&(-i)
using namespace std;
const ll N = 1e6+100;
const ll M=1e5;
const ll mod=1e9+7;
const ll inf=1e18;
const double eps=1e-8;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll n,cnt,head[200005],fac[200005],ifac[200005],dp[100005],siz[100005];
struct Edge{
    ll from,to,next;
}edge[200005];
void addedge(ll from,ll to){
    edge[++cnt].from=from;
    edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt;
}

vector<ll>g[100005];
void init(){
    fac[0]=1;
    for(ll i=1;i<=100000;i++) fac[i]=fac[i-1]*i%mod;
    ifac[100000]=getinv(fac[100000]);
    for(ll i=99999;i>=0;i--)
        ifac[i]=(i+1LL)*ifac[i+1]%mod;
}
void dfs(ll u){
    siz[u]=dp[u]=1;
//    for(int i=head[u];i;i=edge[i].next){
//        ll j=edge[i].to;
//        if(j==fa) continue;
//        dfs(j,u);
//        dp[u]=(dp[u]*dp[j]%mod)*ifac[siz[j]]%mod;
//        siz[u]+=siz[j];
//    }
    for(auto &v:g[u]){
       // cout<<v<<" "<<u<<endl;
        dfs(v);
        dp[u]=(dp[u]*dp[v]%mod)*ifac[siz[v]]%mod;
        siz[u]+=siz[v];
    }
    dp[u]=dp[u]*fac[siz[u]-1]%mod;
}
void dfs(ll u,ll fa){
    siz[u]=dp[u]=1;
    for(int i=head[u];i;i=edge[i].next){
        ll j=edge[i].to;
        if(j==fa) continue;
        dfs(j,u);
        dp[u]=(dp[u]*dp[j]%mod)*ifac[siz[j]]%mod;
        siz[u]+=siz[j];
    }
    dp[u]=dp[u]*fac[siz[u]-1]%mod;
}
int main(){
    scanf("%lld",&n);
    init();
    ll c,a,ans=1,tot=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",&c); tot+=c;
       // for(int j=1;j<=c;j++) g[j].clear();
        for(int j=2;j<=c;j++){
            scanf("%lld",&a);
           // g[a].push_back(j);
            addedge(a,j);
            addedge(j,a);
        }
       // cout<<"halo"<<endl;
        dfs(1,0);
        ans=(ifac[c]*ans%mod)*dp[1]%mod;
         //ans = 1LL * ifac[c] * ans % mod * solve(c) % mod;
        for(int j=0;j<=c;j++) head[j]=edge[j].from=edge[j].to=edge[j].next=0;
    }
    ans=ans*fac[tot]%mod;
    printf("%lld\n",ans);
    return 0;
}