暑期集训2q10

陈太阳的方块

在这里插入图片描述
发现高两层,宽两层,长两层,肯定是被烧过的,所以没有大于2的特判一下,大于二的上公式

#include<bits/stdc++.h>
using namespace std;
inline long long read()
{
    
    
    long long f=1,res=0;char ch=getchar();
    while(!isdigit(ch)){
    
    if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){
    
    res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
    return res*f;
}
long long  n,m,k;
int main()
{
    
    
    n=read();m=read();k=read();
    unsigned long long ans=(n-2)*(m-2)*(k-2);
    cout<<ans;
    return 0;
}
   


陈太阳的算式

在这里插入图片描述
这里提供两种方法
1.打表算出每个可能的值
2.搜索加上栈模拟,算出所以的可能之后,模拟答案

#include<bits/stdc++.h>
using namespace std;
long long tot=0x7fffffff;
long double  ans[100], a,b,c,d,jsq=1;
char aa[5]={
    
    ' ','+','-','*','/'};
int main()
{
    
    
	cin>>a>>b>>c>>d;
	/*for(int i=1;i<=4;i++)
	for(int j=1;j<=4;j++)
	for(int k=1;k<=4;k++)
	{
		cout<<"ans["<<jsq<<"]="<<'a'<<aa[i]<<'b'<<aa[j]<<'c'<<aa[k]<<'d'<<";"<<endl;
		jsq++;
	}*/
ans[1]=a+b+c+d;
ans[2]=a+b+c-d;
ans[3]=a+b+c*d;
ans[4]=a+b+c/d;
ans[5]=a+b-c+d;
ans[6]=a+b-c-d;
ans[7]=a+b-c*d;
ans[8]=a+b-c/d;
ans[9]=a+b*c+d;
ans[10]=a+b*c-d;
ans[11]=a+b*c*d;
ans[12]=a+b*c/d;
ans[13]=a+b/c+d;
ans[14]=a+b/c-d;
ans[15]=a+b/c*d;
ans[16]=a+b/c/d;
ans[17]=a-b+c+d;
ans[18]=a-b+c-d;
ans[19]=a-b+c*d;
ans[20]=a-b+c/d;
ans[21]=a-b-c+d;
ans[22]=a-b-c-d;
ans[23]=a-b-c*d;
ans[24]=a-b-c/d;
ans[25]=a-b*c+d;
ans[26]=a-b*c-d;
ans[27]=a-b*c*d;
ans[28]=a-b*c/d;
ans[29]=a-b/c+d;
ans[30]=a-b/c-d;
ans[31]=a-b/c*d;
ans[32]=a-b/c/d;
ans[33]=a*b+c+d;
ans[34]=a*b+c-d;
ans[35]=a*b+c*d;
ans[36]=a*b+c/d;
ans[37]=a*b-c+d;
ans[38]=a*b-c-d;
ans[39]=a*b-c*d;
ans[40]=a*b-c/d;
ans[41]=a*b*c+d;
ans[42]=a*b*c-d;
ans[43]=a*b*c*d;
ans[44]=a*b*c/d;
ans[45]=a*b/c+d;
ans[46]=a*b/c-d;
ans[47]=a*b/c*d;
ans[48]=a*b/c/d;
ans[49]=a/b+c+d;
ans[50]=a/b+c-d;
ans[51]=a/b+c*d;
ans[52]=a/b+c/d;
ans[53]=a/b-c+d;
ans[54]=a/b-c-d;
ans[55]=a/b-c*d;
ans[56]=a/b-c/d;
ans[57]=a/b*c+d;
ans[58]=a/b*c-d;
ans[59]=a/b*c*d;
ans[60]=a/b*c/d;
ans[61]=a/b/c+d;
ans[62]=a/b/c-d;
ans[63]=a/b/c*d;
ans[64]=a/b/c/d;
for(int i=1;i<=64;i++)if(ans[i]==(int)ans[i])tot=min(abs((long long)ans[i]),tot);//,cout<<abs(ans[i])<<' ';
cout<<tot;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int fh[5],s[5];
int a,b,c,d,ans=0x7fffffff;
inline void get_ans()
{
    
    
    double sz[5],h[5];
    int tep=0,top=0;
    sz[++tep]=s[1];
     
    /*for(int i=1;i<=3;i++)cout<<fh[i]<<' ';
    cout<<endl;*/
    for(int i=1;i<=3;i++)
    {
    
    
      if(fh[i]==1||fh[i]==2)h[++top]=fh[i],sz[++tep]=s[i+1];
      if(fh[i]==3)sz[tep]=sz[tep]*1.0*s[i+1];
      if(fh[i]==4)sz[tep]=sz[tep]*1.0/s[i+1];
    }
    while(top)
    {
    
    
       if(h[top]==1)
       {
    
    
        sz[tep-1]+=sz[tep];
        tep--;
       }
       else
       {
    
    
        sz[tep-1]-=sz[tep];
        tep--;
       }
       top--;
    }
//  cout<<sz[1]<<' ';
    if(sz[1]==(int)sz[1])ans=min(ans,abs((int)sz[1]));
}
inline void dfs(int x)
{
    
    
    if(x==4)
    {
    
    
        get_ans();
        return;
    }
    for(int i=1;i<=4;i++)
    {
    
    
        fh[x]=i;
        dfs(x+1);
    }
}
int main()
{
    
    
    cin>>s[1]>>s[2]>>s[3]>>s[4];
    dfs(1);
    cout<<ans;
    return 0;
}


陈太阳与粉丝在这里插入图片描述

注意到这题无论选取什么样的访问顺序,最终收益都是相同的。那么随便选一种顺序算答案就好了。时间复杂度O(n)。
证明:
使用归纳法。
n=1时,显然答案与顺序无关。现在假设size<n的树的答案与顺序都无关,我们来证明size=n的树的答案与顺序无关。
我们用ANS(x)表示只有根和根的儿子x以及x的子树的子问题的答案,即从根出发,巡游完x的子树并回到根的答案。
我们用SZ(x)表示以x为根的子树的大小的两倍(即从根开始巡游x这个子树再回到根的天数)。
我们假定我们访问根的儿子的顺序是s1,s2…sm,那么总的答案就为ANS(s1)+SZ(s1)(SZ(s2)+SZ(s3)…+SZ(sm))+ANS(s2)+SZ(s2)(SZ(s3)+SZ(s4)+…SZ(sm))+…+ANS(sm)。
注意到总的答案为所有儿子的ANS的和再加上两两儿子之间SZ的积的和。由于儿子至少有两个,所以儿子的子树大小一定小于n,通过归纳法得知它们的ANS与顺序无关。两两儿子之间SZ的积的和也与顺序无关。所以size=n的树的总答案与顺序无关。.

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;
int head[maxn],tot;
struct node
{
    
    
    int u;
    int v;
}edge[maxn];
void add(int x,int y)
{
    
    
    edge[++tot].u=head[x];
    edge[tot].v=y;
    head[x]=tot;
}
long long ans,tep;
int n,m;
void dfs(int x,int fa)
{
    
    
 
    for(int i=head[x];i;i=edge[i].u)
    {
    
    
        int to=edge[i].v;
        if(to!=fa)
        {
    
    
            tep++;
            dfs(to,x);
            tep++;
        }
    }
    ans+=tep;
}
int main()
{
    
    
    cin>>n;
    for(int i=1;i<n;i++)
    {
    
    
        int x,y;cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    cout<<ans;
    return 0; 
}


烤乐滋的最长前缀

在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的序列(即元素)很感兴趣。 如果一个集合 P 中的元素可以通过串联(元素可以重复使用,顺序无需考虑)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素。元素不一定要全部出现(如下例中BBC就没有出现)。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:{A, AB, BA, CA, BBC} 如果序列S前面K个字符可以由某一集合中的元素组成,那么我们就说这K个字符为序列S的一个长度为K的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列 S ,设S’是序列S的最长前缀,使其可以分解为给出的集合P中的元素,求S’的长度K。
设立状态,表达的但是dp[i]前i个字符是不是能拼出来,然后枚举元素集合,判断一下,是不是这个元素可以接上去,如果可以接上去,那么考虑转移

#include<bits/stdc++.h>
using namespace std;
bool  dp[200010];
string s[250],n="",s2;
int k=1,ans;
int main()
{
    
    
    while(cin>>s[k])
    {
    
    
        if(s[k]==".")break;
        k++;
    }
    while(cin>>s2)n=n+s2;
 
     
    dp[0]=1;
    for(int i=1;i<=n.size();i++)
    {
    
    
        for(int j=1;j<=k;j++)
        {
    
    
            int len=s[j].size();
            if(i-len<0)continue;
            /*string ss=n.substr(0,i-len);
            if(ss+s[j]==n.substr(0,i)&&dp[i-len])
            {
                dp[i]=1;
                ans=i;
                break;
            }*/
            int v=len-1,u=i-1;
            while(v>=0)//比较可不可以接上去
            {
    
    
                if(n[u]==s[j][v])v--,u--;
                else break;
            }
            if(v<0&&dp[i-len])
            {
    
    
                             
                dp[i]=1;//标记为可以
                ans=i;
                break;
            }
        }
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yhhy666/article/details/108277182