一点点题

Trees

题意:

有n颗树,要求第i颗和第n-i+1颗高度要相同,并且第i颗和第i+1颗相差为1且递增(对于前一半来说)
现在一个操作是可以把任意一棵树修改为任意高度,给定树的高度序列,求出最小操作数

分析:

因为树的高度要求以1递增,而位置也是递增的,所以如果存在一个序列满足树的高度要求,那么每棵树的高度-所处位置的差相同(对于前一半来说),用n-无需修改的最大值则为修改的最小值

代码:

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
int a[100005];
int main() {
    int n;cin>>n;
    int m;int ans=0;
    for(int i=1;i<=n;i++){
        cin>>m;
        int num=min(i,n-i+1);
        m-=num;
        if(m>=0){
            a[m]++;
            ans=max(ans,a[m]);
        }
    }
    cout<<n-ans;
    return 0;
}

Mushroom Strife

题意:

给定一个n个点m条边的无向图,每个点上对应一个数值,每条边记录着该边所连接的两个节点对应数值的最小公倍数最大公因数。求每个节点上的数值。

分析:

a×b=gcd(a,b)×lcm(a,b)
所以我们只要知道其中一个点的数值,就可以求出与之对应的另一个。因此,我们只要枚举每个连通分量中的一个数就可以推出其中所有的数以及他是否合法。
枚举的方法也很显然dfs即可。
注意会有环

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int N=1e5+10;
#define inf 0x3f3f3f3f
/*
int read(){
    int f=1,x=0;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
*/
struct node{
    int v,g,l;
};
vector<node> a[210];
int ans[210];
bool vis[210];
bool dfs(int x){
    if(vis[x])return true;
    vis[x]=1;
    for(int i=0;i<a[x].size();i++){
        node t=a[x][i];
        if(t.l%ans[x]!=0)return false;
        ll tmp=(t.g*1ll)*(t.l*1ll);
        int k=tmp/ans[x];
        if(__gcd(k,ans[x])!=t.g)return false;
        if(vis[t.v]&&k!=ans[t.v])return false;
        ans[t.v]=k;
        if(!dfs(t.v))return false;
    }
    return true;
}
bool check(int x){
    node t=a[x][0];
    for(int i=t.g;i<=t.l;i+=t.g){
        memset(vis,0,sizeof(vis));
        ans[x]=i;
        if(dfs(x))return true;
    }
    return false;
}
int n,m,e1,e2,g,l;
void solve(){
    memset(ans,0,sizeof(ans));
    cin>>n>>m;
    for(int i=0;i<m;i++){
        cin>>e1>>e2>>g>>l;
        a[e1].push_back({e2,g,l});
        a[e2].push_back({e1,g,l});
    }
    for(int i=1;i<=n;i++){
        if(ans[i]||a[i].size()==0)continue;
        if(!check(i)){
            cout<<"NO"<<endl;return ;
        }
    }
    cout<<"YES"<<endl;
    for(int i=1;i<=n;i++){
        if(ans[i]==0)cout<<"1 ";
        else cout<<ans[i]<<' ';
    }
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

Savior

题意:

给定n个数,任意取两个若能找到一个整数b,使这三个数是毕达哥拉斯三元组,则这两个数能加入到一个优质集合,问要让这n个数都加入到集合中,我最少需要多少个集合。

分析:

毕达哥拉斯三元组: X^2 + Y^2 = Z^2
性质:
假定m,n为任意正整数 (m>n) ,
满足 gcd(m,n) = 1 且 m%2 != n%2
则:
X=m2-n2;
Y=2mn;
Z=m2+n2;

枚举

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int fa[10010000];
int find(int x){
    if(x!=fa[x]) fa[x]= find(fa[x]);
    return fa[x];
}
int gcd(int x,int y){
    while (x^=y^=x^=y%=x);
    return y;
}
int n;
int ans;
void merge(int x,int y){
    if (!fa[x]||!fa[y]) return ;
    int fx=find(x),fy=find(y);
    if(fx!=fy){
        fa[fx]=fy;
        ans--;
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    ans=n;
    for(int i=1;i<=n;i++){
       int x;
       cin>>x;
       fa[x]=x;
    }
    for(int y=1;y<=1e7;y++){
        for(int x=y+1;2*x*y<=1e7&&x*x-y*y<=1e7;x++){
            int a=x*x-y*y;
            int b=2*x*y;
            int c=x*x+y*y;
            if(__gcd(a,b)==1){
                merge(a,b);
                if(c<=1e7){
                    merge(a,c);
                    merge(b,c);
                }
            }
        }
    }
    cout<<ans;
}
    	  	 			  	   								   		

Wormhouse

题意:

给定一条欧拉回路,求字典序比它大的欧拉回路中字典序最小的一条。

分析:

先按原来的路径深搜,dfs添加一个新的参数ok,
当ok为false时,表示当前的路径的字典序不比给定的路径大,当ok为true时,表示当前路径的字典序必定大于给定的路径
当ok为true时,就从小到大去看每一个顶点

代码:

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ll long long

bool a[222][222];
int p[2222];
int ans[2222];
int n,m;
bool dfs(int u,int deep,bool ok){
    int v;
    ans[deep]=u;
    if(deep==m)return ok;
    if(ok)v=1;
    else v=p[deep+1];
    for(int i=v;i<=n;i++){
        if(a[u][i]){
            a[u][i]=false;a[i][u]=false;
            if(i!=p[deep+1]){
                if(dfs(i,deep+1,true))return true;
            }else{
                if(dfs(i,deep+1,ok))return true;
            }
            a[u][i]=true;a[i][u]=true;
        }
    }
    return false;
}
int main() {
    cin>>n>>m;
    for(int i=0;i<=m;i++){
        cin>>p[i];
        if(i>0)a[p[i-1]][p[i]]=a[p[i]][p[i-1]]=true;
    }
    if(dfs(p[0],0,false)){
        for(int i=0;i<=m;i++){
            cout<<ans[i]<<' ';
        }
        cout<<endl;
    }else cout<<"No solution"<<endl;
    return 0;
}

Bulls and Cows

题意:

隐藏一个四位数数字,可以有前导零,且每一位都不同
给出n个可能数字,并给出x:数字(一位)正确且位置正确,y:数字(一位)正确但位置不正确
请确定根据这n个条件能否确定隐藏数字,或回答条件错误

思路:

暴力遍历1000-9999,每个数去判断是否满足所有n个条件

代码:


 #include<bits/stdc++.h>
 using namespace std;
 #define lson l,mid,rt<<1
 #define rson mid+1,r,rt<<1|1
 #define sqr(x) ((x)*(x))
 #define pb push_back
 #define eb emplace_back
 #define maxn 1000006
 #define rep(k,i,j) for(int k=i;k<j;k++)
 typedef long long ll;
 typedef unsigned long long ull;


 int n;
 struct sair{
         int a,b,c;
     }q[15];

 int main(){
         #ifndef ONLINE_JUDGE
    //  freopen("input.txt","r",stdin);
       #endif
       // std::ios::sync_with_stdio(false);
         cin>>n;
        rep(i,0,n) {
                cin>>q[i].a>>q[i].b>>q[i].c;
             }
       int x,y,z;
       int ans,num=0;
         rep(i,0,10000){
                 int tmp=i;
                int a,b,c,d;
                 a=tmp%10,tmp/=10;
                 b=tmp%10,tmp/=10;
                 c=tmp%10,tmp/=10;
                 d=tmp%10;
                 if(a==b||a==c||a==d||b==c||b==d||c==d) continue;
        int flag=1;
                 rep(j,0,n){
                        x=0,y=0,z;
                         tmp=q[j].a;
                         z=tmp%10;
                        if(a==z) x++;
                         if(b==z) y++;
                         if(c==z) y++;
                         if(d==z) y++;
                        tmp/=10;
                        z=tmp%10;
                      if(b==z) x++;
                         if(a==z) y++;
                        if(c==z) y++;
                       if(d==z) y++;
                        tmp/=10;
                        z=tmp%10;
                         if(c==z) x++;
                         if(b==z) y++;
                         if(a==z) y++;
                         if(d==z) y++;
                         tmp/=10;
                         z=tmp%10;
                         if(d==z) x++;
                         if(b==z) y++;
                         if(c==z) y++;
                         if(a==z) y++;
                         if(x!=q[j].b||y!=q[j].c){
                                 flag=0;
                                 break;
                             }
                     }
                 if(flag){
                         num++;
                         ans=i;
                     }
             }
         if(num==0) cout<<"Incorrect data"<<endl;
         else if(num==1) printf("%04d\n",ans);
         else cout<<"Need more data"<<endl;
}

Harry Potter and Three Spells

题意:

a克沙子可变成b克铅,c克铅可变成d克黄金,e克黄金可以变成f克沙子,
问是否可以用一定数量的沙子,得到无限的黄金

分析:

当ace<bdf时,可以
如果0克铅可以换非0克金,也是无限
如果d为0,打死都得不到一点金
ab都是0的时候无法获得铅,就算铅换金很划算也没有意义

代码:

#include <cstdio>
using namespace std;
 
int main()
{
	int a,b,c,d,e,f;
	while (scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f)!=EOF) 
	{
		if(d && (!c || !a&&b) || a*c*e < b*d*f)	printf("Ron\n");
        else	printf("Hermione\n");
	}
	return 0;
}

Petya and His Friends

题意:

要求构造一个n个数的数列,让他们两两之间的最大公约数不为1,但n个数的最大公约数为1

分析:

约数就是一个数的因子
三个数23,25 , 3*5,他们满足两两gcd不为1,但三者的gcd为1,那么我前三个已经满足总的gcd为1了,后面只要选择三个中任意一个的倍数就好了

代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{   
    scanf("%d",&n);
    if(n==2){printf("-1");return 0;}
    printf("6\n10\n15\n");
    for(int i=4;i<=n;i++)printf("%d\n",2*3*(i-2));
    return 0;
}

Petya and Post

题意:

一条环形道路,有n个加油站和n个邮局,每个加油站可加油ai升,相邻两个邮局间距离是bi千米,驾车1升油跑1千米,问从哪几个邮局出发能绕一圈并最终回到出发的那个邮局。(可顺时针或逆时针)

思路:

D1=a1-b1,
D2=(a1+a2)-(b1+b2),
D3=(a1+a2+a3)-(b1+b2+b3),

Dn=(a1+a2+…+an)-(b1+b2+…+bn);

x=min(D(i));如果x>=0那么从这个点走就一定OK。

现在走下一个点,就不需要从头到尾算上一遍了,

D2=a2-b2,
D3=(a2+a3)-(b2+b3),

Dn=(a2+…+an)-(b2+…+bn);
D1=(a1+a2+…+an)-(a1+b2+…+bn);
和前一次相比就是当前的值减去上一点的差值
那么不就把前一次的最小值减去那个点的差值就是下一个点的最小值了

有n段路程,由题意知若已经有n-1段路程可到达,那么这n段路程可到达。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int mm=1e5+9;
const int oo=1e9;
int a[mm],b[mm];
bool vis[mm];
int main()
{
  int n;
  while(cin>>n)
  { memset(vis,0,sizeof(vis));
    for(int i=0;i<n;++i)cin>>a[i];
    for(int i=0;i<n;++i)cin>>b[i];
    int mi=oo,z=0,mmi=oo,zz=0;
    for(int i=0;i<n;++i)
    {z+=a[i]-b[i];zz+=a[n-i-1]-b[(n-i-2+n)%n];//+n是为了取模没有负数
     mi=min(mi,z);mmi=min(mmi,zz);
    }
    int num=0;
    for(int i=0;i<n;++i)
    {
      if(mi>=0&&!vis[i+1])vis[i+1]=1,++num;///找正方向
      if(mmi>=0&&!vis[n-i])vis[n-i]=1,++num;///逆方向
      mi-=a[i]-b[i];
      mmi-=a[n-i-1]-b[(n-i-2+n)%n];
    }
    cout<<num<<"\n";
    for(int i=0;i<=n;++i)
      if(vis[i])
      cout<<i<<" ";
    cout<<"\n";
  }
}
posted @ 2023-09-24 20:44  WW爆米花  阅读(7)  评论(0编辑  收藏  举报