有趣的算法题(三)

Productive Meeting
题意:n个人参加会议,每个人可以和别人交谈ai次,问会议最多有多少次交流
思路:贪心,每次用剩余交谈次数最大和次大的减一。

提醒我要去复习重载运算符了

#include  <bits/stdc++.h>
#define MOD 1000000007;
#define freopen freopen("in.txt","r",stdin);
#define debug cout<<1<<endl;
#define fastio ios::sync_with_stdio(false);cout.tie(false);cin.tie(false);
#define vi vector <int>
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define ll long long
using namespace std;
struct node
{
    int x,y;
};
inline bool operator < (node a,node b)
{
    return a.x<b.x;
}
int main()
{
    //freopen
    int t,n,x;
    node p,temp1,temp2;
    for(cin>>t;t;t--)
    {
        cin>>n;
        priority_queue<node> q;
        vi a,b;
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            if(x==0)
                continue;
            p.x=x,p.y=i;
           q.push(p);
        }
        while(q.size()>=2)
        {
            temp1=q.top();
            q.pop();
            temp2=q.top();
            q.pop();
            temp1.x--;
            temp2.x--;
            ans++;
            a.push_back(temp1.y);b.push_back(temp2.y);
            if(temp1.x>0)
                q.push(temp1);
            if(temp2.x>0)
                q.push(temp2);
        }
        cout<<ans<<endl;
        for(int i=0;i<(int)a.size();i++)
        {
            cout<<a[i]<<" "<<b[i]<<endl;
        }
    }
    return 0;
}

Diameter of Graph

学过离散的图论的话这题应该超级轻松,没学过自己画两个图也能做出来

#include  <bits/stdc++.h>
#define MOD 1000000007;
#define freopen freopen("in.txt","r",stdin);
#define debug cout<<1<<endl;
#define fastio ios::sync_with_stdio(false);cout.tie(false);cin.tie(false);
#define vi vector <int>
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define ll long long
using namespace std;


int main()
{
	int t;
	scanf("%d",&t);
	for(register int i=0;i!=t;i++)
    {
    int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	if((n-1ll)*n>>1<m||m<n-1)
    {
		NO
		continue;
	}
	if(n==1){
		if(k>1){
			YES
		}else{
			NO
		}
	}else if(m<(n-1ll)*n>>1){
		if(k>3){
			YES
		}else{
			NO
		}
	}else if(k>2){
		YES
	}else{
		NO
	}
	}
	return 0;
}

Grandma Capa Knits a Scarf

给你个字符串,你可以删除其中的一种,注意是一种字母。
问:如果删除这种字母就能让字符串变回文串,那么删去那种字母删除字母的个数最少
注:如果咋删都不行,那就输出-1

思路:暴力遍历+贪心(这也能算贪心吗,,,)
对于每个字母删去的情况都遍历一下,取个最小值,复杂度也就26*n,1e6的复杂度肯定不超时。再我也想不出别的方法了

#include<bits/stdc++.h>
using namespace std;
 
int main()
{
 int t;
 
 for(cin>>t;t;t--)
 {
     string s;
     int n;
     int min1=1000000000;
     cin>>n>>s;
     for(char a='a';a<='z';a++)
     {
         int con=0;
         bool falg=true;
         for(int i=0,j=n-1;i<j;)
         {
             if(s[i]==s[j])
             {
                 i++;
                 j--;
                 continue;
             }
             else
             {
                 if(s[i]==a)
                 {
                   i++;
                   con++;
 
                 }
                 else if(s[j]==a)
                 {
                     con++;
                     j--;
                 }
                 else
                 {
                     falg=false;
                     break;
                 }
             }
         }
         if(falg)
         {
             min1=min(min1,con);
         }
     }
     if(min1!=1000000000)
     {
         cout<<min1<<endl;
     }
     else
        cout<<-1<<endl;
 }
}

其实还有很多高效的写法,自己想去吧,,

Array Walk
题意可以自己点进去看

傻了吧,B题就是个DP,还是中等的那种。

这个DP属于一维上的DP,如果要是题目是这样说:我们可以向左走或者向右走,那么就很容易了,可以直接朴素的写一个dp一维的代表第x步向的最大值

但是这个题加上了最多向左走z步

所以设计dp[i][j]为花费i次向左走的机会后站在j的位置上最大获得多少分数

#include  <bits/stdc++.h>
#define MOD 1000000007;
#define freopen freopen("in.txt","r",stdin);
#define debug cout<<1<<endl;
#define fastio ios::sync_with_stdio(false);cout.tie(false);cin.tie(false);
#define vi vector <int>
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define ll long long
#define rint register int
using namespace std;

int a[200000+10],dp[6][200000+10];
int main()
{
    int t,n,k,z;
    //freopen
    for(cin>>t;t;t--)
    {
        cin>>n>>k>>z;
        int maxx=-1;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        for(int i=0;i<=z;i++)
        {
            for(int j=1;j<=n;j++)
            {
                dp[i][j]=dp[i][j-1]+a[j];
                if(i&&j!=n)
                    dp[i][j]=max(dp[i][j],dp[i-1][j+1]+a[j]);
                if(i*2+j-1==k)
                    maxx=max(maxx,dp[i][j]);
            }
        }
        cout<<maxx<<endl;
    }
    return 0;
}

CF1593D2

这是一道纯纯模拟题,看完题意之后看代码就行了,,洛谷上的题解多少有些复杂,,我们还是普通模拟一下吧

#include <bits/stdc++.h>

using namespace std;
 
const int M = 2000010;
int t, n, a[69], b[69], f[M];
 
int main()
{
  cin >> t;
  while (t--) 
  {
       cin >> n;
    for (int i = 0; i < n; ++i)
      cin >> a[i];
    for (int mod = M; mod >= 1; --mod)
    {
      int best = 0;
      for (int i = 0; i < n; ++i)
      {
        b[i] = a[i] % mod;
        if (b[i] < 0) 
          b[i] += mod;
        ++f[b[i]], best = max(best, f[b[i]]);
      }
      for (int i = 0; i < n; ++i)
        --f[b[i]];
      if (best >= n / 2) 
      {
        if (mod == M) 
          mod = -1;
        cout << mod << '\n';
        break;
      }
    }
  }
  return 0;
}
 

AT249 紅茶(Tea)

atcoder的思维题,不涉及算法,是个有意思的思维构造题。

我们能在观察中发现
1.如果分组的话,那么二元数的和相同的就是一个组
2.每个组中,二元数的第二个数代表的就是其这个组中是第几个二元数

#include  <bits/stdc++.h>
#define MOD 1000000007;
#define freopen freopen("in.txt","r",stdin);
#define debug cout<<1<<endl;
#define fastio ios::sync_with_stdio(false);cout.tie(false);cin.tie(false);
#define vi vector <int>
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define ll long long
#define rint register int
using namespace std;

int first,second;
void get(int n)
{
    int sum=2,x=1;
    while(n>1)
    {
        x++;
        if(sum<=x)
        {
            sum++;
            x=1;
        }
        n--;
    }
    first=sum-x;
    second=x;
}
int main()
{
    int a,b;
    cin>>a>>b;
    get(a);
    int f1=first,s1=second;
    get(b);
    int f2=first,s2=second;
    first=0;second=s1+s2;
    for(int i=1;i<=f1+f2+s1+s2-2;i++)
        first+=i;
        cout<<first+second<<endl;
    return 0;
}

明天开篇来一个并查集的逻辑推理题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值