学习笔记11:abc336

人要有自信,人有了自信才会拥有一切

C

分析:仔细观察我们可以发现所谓第k位的规律

第1位  00

第2位  02

第3位  04

第6位  20

第7位  22

第8位  24

这是5个为一个周期的循环

当然周期的下标是从0开始的,所以我们可以在刚开始把  k--

用一个数组记录一下周期

#include <iostream>
#include <cstring>
#include <algorithm>
#
using namespace std;
#define int long long
char a[]={'0','2','4','6','8'};
signed main(){
    int n;
    cin>>n;
    string ans=""; n--;
    if(!n){
        cout<<0<<endl;
        return 0;
    }
    while(n){
       
        int now=n%5;
        ans+=a[now];
      //  cout<<a[now];
        n/=5;
    }
    reverse(ans.begin(),ans.end());
    cout<<ans<<endl;
}

D

dp

环境很重要,你周围的环境(周围的环境只支持你到达这一高度)和你自己的高度(如果自己不努力那么环境再好也没用)取一个最小值

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000010;
int a[N],pre[N],suf[N];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        pre[i]=min(pre[i-1]+1,a[i]);
    }
    int ans=1;
    for(int i=n;i>=1;i--){
        suf[i]=min(suf[i+1]+1,a[i]);
        ans=max(ans,min(pre[i],suf[i]));
    }
    cout<<ans<<endl;
    
}
signed main(){
    int t=1;
    while(t--){
        solve();
    }
}

E

数位dp

分析:数据最高是1e14,那么可能的数位之和只有1-9*14,将每一种可能的数位之和dp,求出答案

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int N = 1000010;
int a[N],pre[N],suf[N];
int dp[50][10*20][10*20];
int m;
int dfs(int cnt,int sum,int mod,int limit){
    if(sum>m) return 0;
    if(!cnt) return sum==m && mod==0;
    if(!limit && dp[cnt][sum][mod]!=-1 ) return dp[cnt][sum][mod];
    int ans=0;
    int e;
    if(limit)e=a[cnt];
    else e=9;
    for(int i=0;i<=e;i++){
        ans+=dfs(cnt-1,sum+i,(mod*10+i)%m,limit && i==a[cnt]);
    }
    if(!limit) dp[cnt][sum][mod]=ans;
    return ans;
}
void solve(){
    int n;
    cin>>n;
    int cnt=0;
    while(n){
        a[++cnt]=n%10;
        n/=10;
    }
    int ans=0;
    for(int i=1;i<=cnt*9;i++){
        m=i;
        memset(dp,-1,sizeof dp);
        ans+=dfs(cnt,0,0,1);
    }
    cout<<ans;
    
}
signed main(){
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
}

F

双向搜索

丑陋的实现:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include<array>
#include<unordered_map>
using namespace std;
#define int long long
const int N = 1000010;
int n,m;
unordered_map<string,int>mp1,mp2;
int get(int x,int y){
    return (x-1)*m+y;
}
void bfs(string tt,int mapid){
    queue<string>q;
    q.push(tt);
    if(mapid==1)mp1[tt]=0;
    else mp2[tt]=0;
    while(q.size()){
        auto t=q.front();
        q.pop();
        if(mapid==1 && mp1[t]>=10) break;
        else if(mapid==2 && mp2[t]>=10) break;
        
        for(int i=0;i<=1;i++){
            for(int j=0;j<=1;j++){//循环改变的位置
                string tmp=t;
                for(int a=1;a<n;a++){
                    for(int b=1;b<m;b++){
                        tmp[get(i+a,j+b)]=t[get(n-a+i,m-b+j)];
                    }
                }
                if(mapid==1 && !mp1.count(tmp) ){
                    mp1[tmp]=mp1[t]+1;
                    q.push(tmp);
                }
                if(mapid==2 && !mp2.count(tmp) ){
                    mp2[tmp]=mp2[t]+1;
                    q.push(tmp);
                }
                
            }
        }
    }
}
void solve(){
    cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);
    
    cin>>n>>m;
    int now=1;
    string start=" ";
    string ed=" ";    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int  x;
            cin>>x;
            start+=(char)(x+'0');
            ed+=(char)(now+'0');
            now++;
        }
    }
    //cout<<start<< " "<<ed<<"\n"; 
    bfs(start,1);
    bfs(ed,2);
    int ans=1e18;
    for(auto c:mp1){
        //cout<<c.first<<endl;
        if(mp2.count(c.first)){
            ans=min(ans,mp1[c.first]+mp2[c.first]);
        }
    }
    if(ans==1e18)cout<<-1<<'\n';
    else cout<<ans<<'\n';
}
signed main(){
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
}

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值