4.9cf自训9..

cf401D 状态压缩dp好题,每次把新加入集合的数字放在最后即可

/*
它可以通过重新排列数字n,
它没有任何前导零,
x除以m后的余数等于0. 

每次把新加的数放在最后 
dp[i][j]表示状态i下模m=j的数量 
dp[i|(1<<k)][j*10+a[k]]+=dp[i][j];

*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll len,n,m,a[20];
ll dp[1<<19][100];
int main(){
    cin>>n>>m;
    while(n)a[++len]=n%10,n/=10;
    dp[0][0]=1;
    for(int i=0;i<(1<<len)-1;i++)
        for(int j=0;j<m;j++)
            for(int k=0;k<len;k++){
                if(i&(1<<k))continue;
                if(i==0&&a[k+1]==0)continue;//前导0 
                dp[i|(1<<k)][(j*10+a[k+1])%m]+=dp[i][j];
            }
    ll cnt[10]={},f[20]={},ans=dp[(1<<len)-1][0];
    f[0]=f[1]=1;
    for(int i=2;i<=18;i++)f[i]=f[i-1]*i;
    for(int i=1;i<=len;i++)cnt[a[i]]++;
    for(int i=0;i<10;i++)
        if(cnt[i])ans/=f[cnt[i]];
    cout<<ans<<endl;    
}
View Code

cf959E 思维题

#include<bits/stdc++.h> 
using namespace std;
#define ll long long
ll n,ans;
ll lowbit(ll x){return x&(-x);} 

int main(){
    cin>>n;
    ll tmp=n,cnt=1;
    while(tmp){
        ans+=tmp/2*cnt;
        tmp/=2,cnt*=2;
    }
    if(n==lowbit(n)){
        cout<<ans<<endl;
        return 0;
    }
    while(n){
        n-=lowbit(n);    ans+=lowbit(n);
    }
    cout<<ans<<endl;return 0;
}
View Code

cf598E dp好题,就是最经典的线性dp,想通了挺简单的

/*
dp[i][j][k]在i*j的方块里吃k大小的代价 
*/
#include<bits/stdc++.h>
using namespace std;
int dp[31][31][51];
int main(){
    for(int i=0;i<=30;i++)
        for(int j=0;j<=30;j++)    
            for(int k=0;k<=50;k++){
                if(k==0 || k==i*j){
                    dp[i][j][k]=0;
                    continue;
                }
                else dp[i][j][k]=100000000;
                for (int h = 0; h <= k; h++){
                    for (int m = 1; m < j; m++)
                        dp[i][j][k] = min(dp[i][j][k], dp[i][m][h] + dp[i][j - m][k - h] + i*i);
                    for (int m = 1; m < i; m++)
                        dp[i][j][k] = min(dp[i][j][k], dp[m][j][h] + dp[i - m][j][k - h] + j*j);
                }
            }
    int t,n,m,k;
    cin>>t;
    while(t--){
        cin>>n>>m>>k;
        cout<<dp[n][m][k]<<endl;
    } 
}
View Code

cf886D 字符串乱搞+判环

#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
 
string s,ans[28];
 
int main()
{
    int i,j,n,f,x,len;
    int vis[28],chu[28],ru[28],mp[28][28];    
    while(cin>>n)
    {
        f=1;
        memset(mp,0,sizeof(mp));    //字符构成的图 
        memset(ru,-1,sizeof(ru));    //每个字符的入度 
        memset(chu,-1,sizeof(chu));    //每个字符的出度 
        //在下面这个循环中,chu/ru=0则说明字符出现过,chu/ru=-1则没出现过 
        for(i=0;i<n;i++)
        {
            cin>>s; //输入字符串 
            memset(vis,0,sizeof(vis)); //用于判断每个字符串中字符出现的次数 
            len=s.length();
            vis[s[0]-'a']++; //首个字符出现次数+1 
            ru[s[0]-'a']=0;  //首个字符出现过 
            chu[s[0]-'a']=0; //首个字符出现过
            for(j=1;j<len;j++)
            { //从第 1 个字符开始建图 
                int u=s[j-1]-'a'; //前一字符 
                int v=s[j]-'a';   //当前字符 
                mp[u][v]=1;
                vis[v]++;
                if(vis[v]>1) f=0; //如果出现次数>1,则输出 NO 
                ru[v]=0;
                chu[v]=0;
            }
        }
        int next[28]; //每个字符的后继字符 
        memset(next,-1,sizeof(next));
        for(i=0;i<26;i++)
            for(j=0;j<26;j++)
                if(mp[i][j])
                { //如果存在边                 
                    ru[j]++;  //入度+1 
                    chu[i]++; //出度+1 
                    next[i]=j; //记录后继 
                }
        for(i=0;i<26;i++)
            if(ru[i]>1||chu[i]>1)
            { //如果有字符的出度或入度 >1则输出 NO 
                f=0;                
                break;
            }
        for(i=0;i<26;i++)
        { //判断是否有环 
            x=i;
            memset(vis,0,sizeof(vis));
            while(x!=next[x])
            {
                if(vis[x]==1)
                { //如果当前元素访问过则有环 
                    f=0;
                    break;
                }
                vis[x]=1;
                x=next[x];
            }
        }
        if(n>351 || !f)
        {
            cout<<"NO"<<endl;
            continue;
        }
        int tol=0;
        for(i=0;i<26;i++) //遍历 26个字符 
            if(ru[i]==0)
            { //如果入度为 0,则会形成一串字符 
                ans[tol]='a'+i;
                x=i;
                while(next[x]!=-1)
                { //加入后继字符 
                    char c=next[x]+'a';
                    ans[tol]+=c;
                    x=next[x];
                }
                tol++;
            }
        sort(ans,ans+tol); //排序    
        for(i=0;i<tol;i++) cout<<ans[i];
        cout<<endl;
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/10680320.html
4.9