暑假集训日记——8.14(codeforce)

这篇博客记录了三道编程题的解题思路:优化图中无3-环的边数,从起点到终点不穿越对角线的棋盘路径数,以及构造元音匹配的美丽歌词。分别涉及图论、动态规划和字符串处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E. 3-cycles
题意:
使得图中不存在长度为3的环,求满足条件的最多边的数目
题解:
二部图的任意两点的最小环长度大于3

#include<bits/stdc++.h>
#define mp make_pair
#define se second
#define fi first
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;

const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353;
double n,m,x,y,z,k,cnt,t,len,q;
double a[N],b[N],c[N];
	//scanf("%lld%lld",&n,&m);
	//printf("%lld\n",ans);
	//for(int i=1;i<=n;i++)
 
int main()
{
	cin >> n ;
	int M = n / 2 ;
	cout << M * ( n - M ) << endl ;
	for ( int i = 1 ; i <= M ; i ++ )
	for ( int j = M + 1 ; j <= n ; j ++ )
		cout << i << " " << j << endl ;
	return 0 ;
}


D - 小兔的棋盘
题意:
小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘,小兔有所失望。不过没过几天发现了棋盘的好玩之处。从起点(0,0)走到终点(n,n)的最短路径数是C(2n,n),现在小兔又想如果不穿越对角线(但可接触对角线上的格点),这样的路径数有多少?
题解:
正常来说可以用结论:
在这里插入图片描述
但是这里直接用组合数会超范围,所以还是直接考虑用卡特兰数的模板

//#include<bits/stdc++.h>
#include<cstdio>
#include<cmath>
#define mp make_pair
#define se second
#define fi first
using namespace std;

typedef long long ll;
//typedef pair<int, int> pii;
//typedef pair<ll, int> pli;
//typedef pair<ll, ll> pll;
typedef long double ld;

const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353;
ll n,m,x,y,z,k,cnt,t,len,q;
ll a[N],b[N],c[N];

ll h[36];
void init()
{
    int i,j;
    h[0]=h[1]=1;
    for(i=2;i<36;i++)
    {
  	h[i]=0;
	for(j=0;j<i;j++)
            h[i]=h[i]+h[j]*h[i-j-1];
    }
}

int main()
{

    cnt=0;
    while(~scanf("%lld",&t))
    {
        cnt++;
        if(t==-1) break;
        init();
        init(2*t);
        printf("%lld %lld %lld %lld\n",cnt,t,h[t]*2);
    }
}

D. Pawn
题意:
国际象棋棋盘最底行站了一个兵。 它只有两种行动方式: 向上左或向上右走。 它可以选择从最低行哪个节点开始他的旅程。 每个格子上有0-9颗豌豆,而士兵想移动到最上一行并且积累到尽可能多的豌豆。同时,因为这个士兵必须把豌豆平均分给自己和他的k个兄弟,他所收集到的豌豆必须是k+1的倍数。请找到他可以收集到的最多豌豆,并确定他的操作序列。
规定士兵不能手动扔出豌豆,并且他必须捡起所到达的每一个格子的所有豌豆。
题解:动态规划
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示 i i i j j j列 数字和为 k k k的状态是否存在
一开始想用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示这一点处的数字和来转移,但同一个点会有很多数字和的情况,而且不确定那个是需要的,所以还需要再加一维。

#include<bits/stdc++.h>
#define mp make_pair
#define se second
#define fi first
using namespace std;

typedef long long ll;
//typedef pair<int, int> pii;
//typedef pair<ll, int> pli;
//typedef pair<ll, ll> pll;
typedef long double ld;

const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353;
int n,m,x,y,z,k,cnt,t,len,q;
char a[200][200];
int maps[200][200];
int dp[200][200][1500];
char vis[N];


int main()
{
	scanf("%d%d%d",&n,&m,&k);
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;i++)
    {
        scanf("%s",a[i]+1);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            maps[i][j]=a[i][j]-'0';
        }
    }
    for(int i=1;i<=m;i++)
    {
        dp[n][i][maps[n][i]]=1;
    }
    for(int i=n-1;i>=1;i--)
    {
        for(int j=1;j<=m;j++)
        {
            int now=maps[i][j];
            for(int p=now;p<=1100;p++)
            {
                int l=0,r=0;
                if(j-1>=1) l=dp[i+1][j-1][p-now];
                if(j+1<=m) r=dp[i+1][j+1][p-now];
                dp[i][j][p]=max(l,r);
                //if(dp[i][j][p]==1)
                //printf("%d %d %d   %d-%d\n",i,j,p,l,r);
            }
        }
    }
    int pos,ans=-1;
    for(int j=1;j<=m;j++)
    {
        for(int l=0;l<=1100;l++)
        {
            if(dp[1][j][l]==1&&l%(k+1)==0)
            {
                if(l>ans)
                {
                    ans=l;
                    pos=j;
                }

            }
        }
    }
    cnt=0;
    printf("%d\n",ans);

    if(ans!=-1)
    {
        for(int i=2;i<=n;i++)
        {
            int now=maps[i-1][pos];
            int pre=ans;
            if(pos-1>=1&&dp[i][pos-1][pre-now]==1)
            {
                vis[++cnt]='R';
                pos=pos-1;
                ans=pre-now;
                continue;
                //如果左侧符合pos改变,下面的循环pos的意义就变了
            }
            if(pos+1<=m&&dp[i][pos+1][pre-now]==1)
            {
                vis[++cnt]='L';
                pos=pos+1;
                ans=pre-now;
            }

        }
        printf("%d\n",pos);
        for(int i=cnt;i>=1;i--)
            printf("%c",vis[i]);
        printf("\n");
    }
}

C. Beautiful Lyrics
题意:
给定n个单词,每个单词由小写字母组成。每个单词至少包含一个元音。你将选择一些给定的单词,并尽可能多地写出优美的歌词。
每首抒情诗由两行组成。每一行由两个由空格分隔的单词组成。
歌词是美丽的,当且仅当它满足以下所有条件。
第一行第一个单词的元音个数与第二行第一个单词的元音个数相同。
第一行第二个单词的元音个数与第二行第二个单词的元音个数相同。
第一行的最后一个元音与第二行的最后一个元音相同。注意,元音后面可能有辅音。

题解:字符串模拟题
需要维护 一个单词中元音的个数和结尾元音
元音的个数相等单词的对数= N N N,以相同元音结尾的单词的对数= M M M
题目不难就是思路要想清楚,不然会很乱套,首先可以确定美丽歌词的数目。
美丽歌词的数目= m i n ( N / 2 , M ) min(N/2,M) minN/2M
确定了歌词数目后,由于M 可能会多,不可能会少,因为第二个单词,必须是相同元音结尾,多的就去补第一个单词。
所以先向 v q vq vq中塞答案,然后往 v p vp vp中塞答案

#include<bits/stdc++.h>
#define mp make_pair
#define se second
#define fi first
using namespace std;

typedef long long ll;
//typedef pair<int, int> pii;
//typedef pair<ll, int> pli;
//typedef pair<ll, ll> pll;
typedef long double ld;

const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353;
int n,m,x,y,z,k,cnt,t,len,q;
string str[N];
vector<int>s[N][6];///s[i][j]储存 长度为i 结尾为j 的单词
int v[100];
vector<int> vp;///诗歌的第一句
vector<int> vq;///诗歌的第二句
vector<int> tmp[N];

int main()
{
    cin>>n;
    v['a'-'a']=1;
    v['e'-'a']=2;
    v['i'-'a']=3;
    v['o'-'a']=4;
    v['u'-'a']=5;
    for(int i=0;i<n;i++)
    {
        cin>>str[i];
        int sum=0;int pos=0;
        for(int j=0;j<str[i].length();j++)
        {
            if(v[str[i][j]-'a'])
                sum++,pos=v[str[i][j]-'a'];

        }
        if(sum>0)
        s[sum][pos].push_back(i);

    }
    int num1=0,num2=0;
    for(int i=1;i<N;i++)///计算有多少列
    {
        int sum=0;
        for(int j=1;j<=5;j++)
        {
            sum+=s[i][j].size();
            num2+=s[i][j].size()/2;
        }
        num1+=sum/2;
    }
    int ans=min(num1/2,num2);
    cout<<ans<<endl;
    k=ans;
    for(int i=1;i<N;i++)
    {
        for(int j=1;j<=5;j++)
        {
            for(int p=0;p<s[i][j].size();p++)
            {
                if(p+1<s[i][j].size()&&k)
                {
                    vq.push_back(s[i][j][p]);
                    p++;
                    vq.push_back(s[i][j][p]);
                    k--;
                }
                else
                {
                    tmp[i].push_back(s[i][j][p]);
                }
            }
        }
    }
    k=ans;
    for(int i=1;i<N;i++)
    {
        for(int p=0;p<tmp[i].size();p++)
        {
            if(p+1<tmp[i].size()&&k)
            {
                vp.push_back(tmp[i][p]);
                p++;
                vp.push_back(tmp[i][p]);
                k--;
            }
        }
    }
    for(int i=0;i<vp.size();i++){
        cout<<str[vp[i]]<<" "<<str[vq[i]]<<endl;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值