A:水过


B:模拟题水过

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
#define bug cout <<"bug" <<endl

using namespace std;
typedef long long ll;

char s1[500],s2[500];
int cnts[50];
int cntt[50];

int check(){
        int i,j,n,m,dp[1000],book[1000],s;
		n=strlen(s1);
		m=strlen(s2);
		for(i=1;i<=n;i++)
		{
			s=0;
			for(j=1;j<=m;j++)
			{
				if(s1[i-1]==s2[j-1])
					dp[j]=book[j-1]+1;
				else if(dp[j-1]>book[j])
					dp[j]=dp[j-1];
				else
					dp[j]=book[j];
				book[j-1]=s;
				s=dp[j];
			}
			book[m]=s;
		}
		return  dp[m];
}

int main(void){
    scanf("%s%s",s1,s2);
    int len1=strlen(s1),len2=strlen(s2);
    for(int i=0;i<len1;i++) cnts[s1[i]-'a'+1]++;
    for(int i=0;i<len2;i++) cntt[s2[i]-'a'+1]++;
    for(int i=1;i<=26;i++){
        if(cntt[i]>cnts[i]){
                //cout <<"i="<<i<<endl;
                //cout <<cntt[i] << " "<<cnts[i];
            printf("need tree\n");
            return 0;
        }
    }
    bool flag1=false,flag2=false;
    if(len1>len2)   flag1=true;
    int ans=check();
    if(ans!=len2)   flag2=true;
    if(flag1==true && flag2==true)  cout <<"both"<<endl;
    else if(flag1==true && flag2==false)    cout <<"automaton"<<endl;
    else if(flag1==false && flag2==true)    cout <<"array"<<endl;
    return 0;
}

C:

题意:给定n个连续栅栏宽度1m,高度各不相同,现在有一把刷子宽度1m,只能横刷或者竖刷,遇到有断裂的地方就不能继续刷。 问,至少刷几次才能刷玩。


思路:

1.n一定是一个合理答案,即全部竖刷

2.为了求更优解,我们尝试着使用部分横刷去弥补竖着刷带来的不足。

3.如何确定横着刷带来的最大效益呢?  假设当前hmin为高度最小的栅栏,那么我们把所有的点都减去hmin,那么剩下来的部分又会出现下一个hmin,以0作为区间的划分标准,答案最小值又是当前hmin和当前的栅栏个数Xi。如此递归下去,直至当l==r时,返回1.

#include <bits/stdc++.h>
#define bug cout <<"bug" <<endl

using namespace std;
typedef long long ll;

int n;
int a[5005];

int dfs(int l,int r){
    int mmin=a[l];
    int ans1=r-l+1;
    for(int i=l+1;i<=r;i++)
        if(a[i]<mmin)   mmin=a[i];
    int ans=mmin;
    for(int i=l;i<=r;i++)   a[i]-=mmin;
    for(int i=l;i<=r;i++){
        if(a[i]){
            int nl=i;
            int nr=i;
            while(nr<=n&&a[nr]) nr++;
            nr--;
            ans+=dfs(nl,nr);
        }
    }
    return min(ans1,ans);
}

int main(void){
    cin >> n;
    for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
    printf("%d\n",dfs(1,n));
}

D

题意:n*m的矩阵a[i][j]=i*j   问第k大为多少


思路:  注意题意!第k大的定义是从小到大非递减序列的第k个。 那么二分答案即可,利用在n*m的矩阵中有性质:比x小的数cnt= x/i个 (i属于1~n)

二分,如果cnt >=k  那么  记录ans=mid,   r=mid-1; else , l=mid+1


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
#define bug cout <<"bug" <<endl

using namespace std;
typedef long long ll;

ll n,m,k;
ll check(ll x){
    ll cnt=0;
    for(int i=1;i<=n;i++)   cnt+=min(x/i,m);
    return cnt >= k;
}

int main(void){
    cin >> n >>m >>k;
    ll l=1,r=n*m;
    ll ans;
    while(l<=r){
        ll mid=(l+r)/2;
        if(check(mid))  ans=mid,r=mid-1;
        else    l=mid+1;
    }
    cout << ans << endl;
}

E

题意:把x进行质因数分解k次,对其所有质因数再分解质因数直至1或者k==0。

思路:DFS ,如果n==1或者k==0 return ;  这里有一个性质:x的质因数  的 质因数 仍在 x的质因数范围内。因为x是这个数的整数倍。


#include <bits/stdc++.h>
#define bug cout <<"bug"<<endl

using namespace std;
typedef long long ll;

const int N=1e7+5;
ll vec[N];
ll cnt=0,cur=0;
ll len;

void DFS(ll n,ll k){
    if(cnt>=1e5) return ;
    if(k==0 || n==1){
        printf("%lld ",n);
        cnt++;
        return ;
    }
    //cout <<"len="<<len<<endl;
    for(register ll i=0;i<len && n>=vec[i];i++)
        if(n%vec[i]==0) DFS(vec[i],k-1);
}

int main(void){
    ll x,k;
    scanf("%lld%lld",&x,&k);
    for(register ll i=1;i*i<=x;i++){
        if(x%i==0){
            vec[cur++]=i; 
            if(x/i!=i)  vec[cur++]=x/i;
        }
    }
    sort(vec,vec+cur);
    len=cur;DFS(x,k);
    //cout <<"cnt="<<cnt<<endl;
}