ccf-csp 2021-2018题目总结(部分)

2021-04

DHCP服务器

注意结构体里面存放了什么,注意每次刷新IP的状态

#include<stdio.h>
#define MAX(x,y)  (((x)>(y))?(x):(y))
#define MIN(x,y)  (((x)<(y))?(x):(y))
#include<string.h>
const int MAXN=1e4+5;
typedef long long ll;
char zj[25];
char post[25],get[25],kind[20];
ll t,tmin,tmax,tdft;
ll address;
ll ot;
ll step,T;
ll maxn,nowtime;
struct st
{
	ll state;   	//0 未分配 1 待分配 2 占用 3 过期
	ll outtime;		//过期时间 
	char owner[25];
} ip[10005];
void brush()
{
	ll i;
	for( i=1; i<=maxn; i++)
		if(ip[i].outtime<=nowtime)
			{
				if(ip[i].state==2)
					ip[i].state=3;
				if(ip[i].state==1)
					{
						ip[i].state=0;
						strcpy(ip[i].owner,"");
					}
			}
}
ll checkusedip()
{
	ll i;
	for( i=1; i<=maxn; i++)
		if(strcmp(ip[i].owner,post)==0)
			return i;
	for( i=1; i<=maxn; i++)
		if(ip[i].state==0)
			return i;
	for( i=1; i<=maxn; i++)
		if(ip[i].state==3)
			return i;
	return 0;
}
int solve()
{
	brush();
	if(strcmp(get,zj)!=0&&strcmp(get,"*")!=0)
		{
			if(strcmp(kind,"REQ")!=0)
				return 0;
		}
	if(strcmp(kind,"DIS")!=0&&strcmp(kind,"REQ")!=0)
		return 0;
	if(strcmp(get,"*")==0&&strcmp(kind,"DIS")!=0)
		return 0;
	if(strcmp(get,zj)==0&&strcmp(kind,"DIS")==0)
		return 0;
	if(strcmp(kind,"DIS")==0)			//discover
		{
			ll f;
			f=checkusedip();
			if(!f) return 0;
			ip[f].state=1;
			strcpy(ip[f].owner,post);
			if(ot==0)
				{
					ip[f].outtime=nowtime+tdft;
				}
			else
				{
					ll newot=ot;
					newot=MAX(nowtime+tmin,newot);
					newot=MIN(nowtime+tmax,newot);
					ip[f].outtime=newot;
				}
			printf("%s %s OFR %lld %lld\n",zj,post,f,ip[f].outtime);
		}
	else if(strcmp(kind,"REQ")==0)		//request
		{
			if(strcmp(get,zj)!=0)
				{
					ll i;
					for(i=1; i<=maxn; i++)
						{
							if(strcmp(ip[i].owner,post)==0)
								{
									if(ip[i].state ==1) 
										{
											ip[i].state=0;
											strcpy(ip[i].owner,"");
											ip[i].outtime=0;
										}
								}
						}
					return 0;
				}
			if(address>maxn||strcmp(ip[address].owner,post)!=0)
				{
					printf("%s %s NAK %lld 0\n",zj,post,address);
					return 0;
				}
			if(ot==0)
				ip[address].outtime=nowtime+tdft;
			else
				{
					ll newot=ot;
					newot=MAX(nowtime+tmin,newot);
					newot=MIN(nowtime+tmax,newot);
					ip[address].outtime=newot;
				}
			ip[address].state=2;
			printf("%s %s %s %lld %lld\n",zj,post,"ACK",address,ip[address].outtime);
		}
	return 0;
}
int main()
{
	scanf("%lld%lld%lld%lld%s",&maxn,&tdft,&tmax,&tmin,zj);
	ll i;
	for(i=0; i<=maxn; i++)
		{
			ip[i].outtime=0;
			ip[i].state=0;
			strcpy(ip[i].owner,"");
		}
	scanf("%lld",&T);
	while(T--)
		{
			scanf("%lld%s%s%s%lld%lld",&nowtime,post,get,kind,&address,&ot);
			solve();
		}
	return 0;
}

校门外的树

参考
此题极具学习价值,不学后悔系列😆
解答本题有两个关键点,动态规划和约数优化加速。
设障碍物编号为:a[0]~a[n-1],f[i]为到第i个障碍物的方案总数,则有状态转移方程为:
f[i]=∑ j = 0 i − 1 f [ j ] \sum_{j=0}^{i-1} f[j]∑
j=0
i−1

f[j] * cnt(j,i) , f[0]=1
其中cnt(j, i)为第j个障碍物到第i个障碍物之间的方案数,注意这里是把a[j]和a[i]之间看作一个整体进行植树,不考虑分割情况,即在此区间里所有的树和a[j]、a[i]构成等差数列。这里我们可能一时间想不出来为什么状态转移方程会是这样,以及这样真的可以不重不漏地列举出所有的方案吗?
真的耶✌
嘿嘿,别捉急,我们看个栗子就明白了~

假设有三个障碍物:a0=0, a1=4, a2=10,很容易得知当前的方案数为2*3+1=7种。
其中2、3、1分别是a0和a1、a1和a2、a0和a2之间的方案数。
换一种计算方式:7=f[1]*cnt(1,2)+f[0]*cnt(0,2)
其中f[0]=1为初始设定,f[1]=2为a0和a1之间的方案数(取间隔为1、2),cnt(1,2)=3为a1和a2之间的方案数(取间隔为1、2、3),cnt(0,2)=1为a0和a2之间的方案数(取间隔为5)
到这里相信大家已经明白上述状态转移方程的逻辑了,关于更多障碍物的例子,大家不妨自己试试,使用上述动态规划方法能否不重不漏。

只要想到了动态规划,这道题基本上可以拿到60分了,满分解答此题的第二个关键在于怎么优化cnt(j,i)的计算。
我们很容易想到,第j个障碍物到第i个障碍物之间的 植树间隔 必须为a[i] - a[j]的 因子,方案数一定小于等于因子个数,因为这个间隔还不能撞上a[j]和a[i]之间的障碍物。我们倒着从i - 1开始枚举j,这样一开始i - 1和i之间是没有障碍物的,则a[i] - a[i - 1]的所有因子都满足条件;然后到了i - 2,同样先枚举a[i] - a[i - 2]的所有因子,这些因子中已经处于集合中的一定不可,等于a[i]-a[i-1]的也不可,因为按这样的间隔排列一定会有树遇上a[i - 1]这个障碍物;以此类推,倒着枚举到a[i] - a[k]因子的时候,如果已经在之前的枚举中使用过,则跳过,否则方案数就加一。我们使用一个状态数组st[M],保存某个因子是否已经使用过了,不要忘记外循环每一次都要先把状态数组清空,以及使用筛法预处理出1e5范围内每个数的因子

#include <stdio.h>
#include <cstring>
#include <vector>

using namespace std;
typedef long long LL;
const int N = 1010, M=100010, mod=1e9+7;

int n, cnt=0;
int f[N], a[N];
vector<int> q[M];	//保存可能用到的所有距离的因子
bool st[M];	//状态数组
int main()
{
    for(int i=1; i<M; i++){	//使用倍数进行预处理,巧妙计算出每个数的因子
        for(int j=2*i; j<M; j+=i){
            q[j].push_back(i);
        }
    }
    f[0]=1;	//初始设定
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",a+i);
    }
    for (int i = 1; i < n; i ++ ){	//每轮添加一个障碍物,计算添加后的方案总数
        memset(st, 0, sizeof(st));	//清空状态数组
        for(int j=i-1;j>=0;j--){
            int d = a[i]-a[j];cnt=0;
            for(int k : q[d]){	//枚举d的所有因子,其实就是所有可能的方案
                if(!st[k]){	//如果此因子之前没使用过,方案数加一,并标记当前因子已被用过
                    cnt++;
                    st[k]=true;
                }
            }
            st[d]=true;	//手动添加d本身,因为下一轮如果按照这个间隔植树就会撞上本轮添加的障碍物
            			//因为最后一个障碍物必选。。
            f[i]=(f[i]+(LL)f[j] * cnt)%mod;	//更新方案总数
        }
    }
    printf("%d\n",f[n-1]);
    return 0;
}

疫苗运输

2020-12⭐

带配额的文件系统

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
#include <limits.h>
using namespace std;
const int maxn = 4e6 + 5;
typedef long long int ll;
struct Node {
    map<string, int> child;//孩子的名字+孩子的下标
    ll max_ld1, max_ld2;//max_ld1:目录配额,max_ld2:后代配额
    ll ld1, ld2;//max_ld1:现有的目录配额,max_ld2:现有的后代配额
    ll fsize;//文件大小
    int flag;//1为文件,2为目录
    int fa_id;//父亲的下标
};
Node node[maxn];//数据结构:静态树
int n, index = 0;

vector< pair<int, string> > reback;
void Reback()//妙妙妙
{
    int i;
    for (i = 0; i < (int)reback.size(); i++)
    {
        int f_id = reback[i].first;
        string son_name = reback[i].second;
        node[f_id].child.erase(son_name);
    }
}
string Cdo()
{
    //第一步:两个输入,找出最后的/
    string path; ll fsize;
    cin >> path >> fsize;
    int last = path.rfind("/");
    /***********************/
    int p = 1;
    int id = 0;
    int tindex = index;
    reback.clear();
    while (p < last)
    {
        string t = "";
        for (; p < last && path[p] != '/'; p++)
        {
            t += path[p];
        }
        p++;
        if (node[id].child.find(t) == node[id].child.end())
        {
            node[id].child[t] = ++index;
            node[index].fa_id = id;
            node[index].flag = 2;
            node[index].max_ld1 = LLONG_MAX / 3;
            node[index].max_ld2 = LLONG_MAX / 3;
            reback.push_back(make_pair(id, t));
            id = index;
        }
        else {
            int sonid = node[id].child[t];
            if (node[sonid].flag == 1) { index = tindex; Reback(); return "N"; }
            id = sonid;
        }
    }
    /*******到此目录部分已处理********/
    string f_name = path.substr(last + 1);//取出要创建的文件名
    if (node[id].child.find(f_name) != node[id].child.end())
    {
        int sonid = node[id].child[f_name];
        if (node[sonid].flag == 2) { index = tindex; Reback(); return "N"; }
    }
    /***********到此,“若路径所指文件已经存在,但是目录文件的,则该指令不能执行成功”处理完毕**********/
    ll py;//记录增加的文件大小,验证假设创建之后的配额情况
    if (node[id].child.find(f_name) == node[id].child.end())
        py = fsize;
    else if (node[id].child.find(f_name) != node[id].child.end())
        py = fsize - node[node[id].child[f_name]].fsize;
    if (node[id].ld1 + py > node[id].max_ld1) { index = tindex; Reback(); return "N"; }//验证父亲的目录配额
    int temp_id = id;
    while (temp_id != -1)//验证祖先的后代配额
    {
        if (node[temp_id].ld2 + py > node[temp_id].max_ld2) { index = tindex; Reback(); return "N"; }
        temp_id = node[temp_id].fa_id;
    }
    /*********到此配额已经检查完毕*************/
    if (node[id].child.find(f_name) == node[id].child.end())//要么创建
    {
        node[id].child[f_name] = ++index;
        node[index].fa_id = id;
        node[index].flag = 1;
        node[index].fsize = fsize;
    }
    else if (node[id].child.find(f_name) != node[id].child.end())//要么替换,修改大小即可
    {
        int sonid = node[id].child[f_name];
        node[sonid].fsize = fsize;
    }
    node[id].ld1 += py;//修改父亲的现有的目录配额
    int temp_id2 = id;
    while (temp_id2 != -1)//修改祖先的现有的后代配额
    {
        node[temp_id2].ld2 += py;
        temp_id2 = node[temp_id2].fa_id;
    }
    return "Y";
}

string Rdo()
{
    string path;
    cin >> path;
    int last = path.rfind('/');
    /**********************************/
    int p = 1;
    int id = 0;
    while (p < last)
    {
        string t = "";
        for (; p < last && path[p] != '/'; p++)
        {
            t += path[p];
        }
        p++;
        if (node[id].child.find(t) == node[id].child.end()) { return "Y"; }
        else {
            int sonid = node[id].child[t];
            if (node[sonid].flag == 1) { return "Y"; }
            id = sonid;
        }
    }
    /*************目录处理完毕*****************/
    string f_name = path.substr(last + 1);
    if (node[id].child.find(f_name) == node[id].child.end())
        return "Y";
    if (node[id].child.find(f_name) != node[id].child.end())
    {
        int sonid = node[id].child[f_name];
        if (node[sonid].flag == 1) //如果是文件
        {
            node[id].child.erase(f_name);
            node[id].ld1 -= node[sonid].fsize;//修改父亲的现有的目录配额
            int temp_id = id;
            while (temp_id != -1)//修改祖先的现有的后代配额
            {
                node[temp_id].ld2 -= node[sonid].fsize;
                temp_id = node[temp_id].fa_id;
            }
        }
        else if (node[sonid].flag == 2)//如果是目录
        {
            node[id].child.erase(f_name);
            int temp_id = id;
            while (temp_id != -1)//修改祖先的现有的后代配额
            {
                node[temp_id].ld2 -= node[sonid].ld2;
                temp_id = node[temp_id].fa_id;
            }
        }
    }
    return "Y";
}

string Qdo()
{
    string path;
    ll set_ld1, set_ld2;
    cin >> path >> set_ld1 >> set_ld2;
    if (set_ld1 == 0) set_ld1 = LLONG_MAX / 3;
    if (set_ld2 == 0) set_ld2 = LLONG_MAX / 3;
    int last = path.rfind('/');
    /**********************************/
    int p = 1;
    int id = 0;
    while (p < last)
    {
        string t = "";
        for (; p < last && path[p] != '/'; p++)
        {
            t += path[p];
        }
        p++;
        if (node[id].child.find(t) == node[id].child.end()) { return "N"; }
        else {
            int sonid = node[id].child[t];
            if (node[sonid].flag == 1) { return "N"; }
            id = sonid;
        }
    }
    /***************************************/
    string f_name = path.substr(last + 1);
    int qnode;//代表要修改配额的目录
    if (f_name.size() == 0)//是根目录
        qnode = 0;
    else {
        if (node[id].child.find(f_name) == node[id].child.end()) return "N";//没有这个目录
        else qnode = node[id].child[f_name];
    }
    if (node[qnode].flag == 1) return "N";//是文件
    else {
        if (set_ld1 < node[qnode].ld1 || set_ld2 < node[qnode].ld2) return "N";//检查配额
        else {
            node[qnode].max_ld1 = set_ld1;
            node[qnode].max_ld2 = set_ld2;
            return "Y";
        }
    }
}
int main()
{
    node[0].fa_id = -1; node[0].flag = 2; node[0].max_ld1 = LLONG_MAX / 3; node[0].max_ld2 = LLONG_MAX / 3;
    int i;
    string str;
    char c;
    cin >> n;
    for (i = 0; i < n; i++)
    {
        cin >> c;
        if (c == 'C')
        {
            cout << Cdo() << '\n';
        }
        if (c == 'R')
        {
            cout << Rdo() << '\n';
        }
        if (c == 'Q')
        {
            cout << Qdo() << '\n';
        }
    }
    return 0;
}



食材运输

在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int n, m, k;
int request[101];  //利用位运算,记录每一个酒店是否需要该石材 
int flag[101];     //记录特定酒店对食材需要的情况
int road;
int G[101][20];    //存放车从每一个酒店节点出发送每一种食材的所需时间的最大值
int dp[12][1025], tmp[12][1025];
int T[101];
struct  node
{
	int v, w;
};
vector<node>graph[101];
int dfs(int u, int fa)
{
	int mx = 0;
	int i;
	for (i = 0; i < graph[u].size(); i++)
	{
		int v = graph[u][i].v;
		int w = graph[u][i].w;
		if (v == fa) continue;//防止重复计算
		int re = dfs(v, u);//深度优先搜索
		if (flag[v])//这个节点酒店对该食材有需求
		{
			flag[u] = 1;
			road = road + w;
			mx = max(mx, w + re);
		}
	}
	return mx;
}
int judge(int mid)
{
	int i, j, ii;
	memset(dp, 0, sizeof(dp)); //动态规划数组
	memset(T, 0, sizeof(T));  //记录每一个节点在满足mid的条件下可以运输食材的情况
	for (i = 1; i <= n; i++)
		for (j = 0; j < k; j++)
			if (G[i][j] <= mid) T[i] |= (1 << j); 
	tmp[0][0] = dp[0][0] = 1; //初始化
	for (i = 1; i <= n; i++) //枚举每一个节点
	{
		for (j = 1; j <= m; j++)  
		{
			memcpy(tmp, dp, sizeof(dp)); //状态压缩带来的状态复制
			for (ii = 0; ii < (1 << k); ii++) //枚举,每一种已经运输的情况
			{
				dp[j][ii] |= tmp[j][ii];
				dp[j][ii | T[i]] |= tmp[j - 1][ii]; //状态更新
			}
		}
	}
	return dp[m][(1 << k) - 1]; //返回是否满足条件
}
int main()
{
	int i, j;
	//输入
	cin >> n >> m >> k;
	//记录每一个酒店对食材的需要情况
	for (i = 1; i <= n; i++)
	{
		for (j = 0; j < k; j++)
		{
			int x;
			cin >> x;
			if (x == 1) request[i] |= (1 << j); //位运算的思想
		}
	}
	//双向建图
	for (i = 1; i < n; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		graph[u].push_back({ v,w });
		graph[v].push_back({ u,w });
	}
	//预处理
	for (i = 1; i <= n; i++)
	{
		for (j = 0; j < k; j++)
		{
			memset(flag, 0, sizeof(flag));
			for (int ii = 0; ii <= n; ii++)
				if ((request[ii] >> j) & 1) flag[ii] = 1;
			road = 0;
			//从该出发点到最远的叶子节点酒店的最远距离
			int mx = dfs(i, -1);
			//算法分析中已经推导了这个公式
			G[i][j] = road * 2 - mx;
		}
	}
	int l = 1, r = 1e9, ans;
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (judge(mid))//满足条件就继续缩小
		{
			r = mid - 1;
			ans = mid;
		}
		else l = mid + 1; //不满足条件,就进行扩大
	}
	cout << ans;
	return 0;
}

星际旅行

#include<bits/stdc++.h>
using namespace std;
int n,m;
double r;
struct point
{
    double d[110];
}p[2010];
double ans[2010];
point o;
double x[2010],diso[2010];

bool intersect(int x,int y,double c)
{
    double b=diso[x],a=diso[y];
    double p=(a+b+c)/2;
    double s=sqrt(p*(p-a)*(p-b)*(p-c));
    double h=2*s/c;
    if(h<r)
    {
        if((b*b+c*c-a*a)>0&&(a*a+c*c-b*b)>0)
        return 1;
    }
    return 0;
}

int main()
{
    cin>>n>>m>>r;
    for(int i=1;i<=n;i++) cin>>o.d[i];
    for(int i=1;i<=m;i++)
    {
        double s=0;
        for(int j=1;j<=n;j++)
        {
            cin>>p[i].d[j];
            p[i].d[j]-=o.d[j];
            s+=p[i].d[j]*p[i].d[j];
        } 
        diso[i]=sqrt(s);
        x[i]=sqrt(s-r*r);
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=i+1;j<=m;j++)
        {
            double c=0,ang;
            double d;
            for(int k=1;k<=n;k++) c+=(p[i].d[k]-p[j].d[k])*(p[i].d[k]-p[j].d[k]);
            c=sqrt(c);
            if(intersect(i,j,c))
            {
                double angj=acos(r/diso[j]),angi=acos(r/diso[i]);
                ang=acos((diso[i]*diso[i]+diso[j]*diso[j]-c*c)/(2*diso[i]*diso[j]));
                double anga=ang-angj-angi;
                d=x[i]+x[j]+anga*r;
            }
            else d=c;
            //printf("%d %d %.16f\n",i,j,d);
            ans[i]+=d,ans[j]+=d;
        }
    }
    for(int i=1;i<=m;i++)
        printf("%.15lf\n",ans[i]);
    return 0;
}

2020-09⭐

点亮数字人生

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
struct Node{
    int opt;
    vector<int>In;
    vector<int>Out;
}Dev[505];
int Input[N][505],Ind[505],ans[505];
vector<int>e[505];
int getNum(int pos,char *str){
    int num=0;
    int len=strlen(str);
    while(pos<len){
        num=num*10+str[pos]-'0';
        ++pos;
    }
    return num;
}
int Operation(vector<int>q,int opt){
    if(opt==0) return !q[0];
    else{
        int cnt=q.size();
        int r=q[0];
        if(opt==1){
            for(int i=1;i<cnt;++i) r&=q[i];
            return r;
        }
        else if(opt==2){
            for(int i=1;i<cnt;++i) r|=q[i];
            return r;
        }
        else if(opt==3){
            for(int i=1;i<cnt;++i) r^=q[i];
            return r;
        }
        else if(opt==4){
            for(int i=1;i<cnt;++i) r&=q[i];
            return !r;
        }
        for(int i=1;i<cnt;++i) r|=q[i];
        return !r;
    }
}
int dfs(int s,int u){
	if(ans[u]!=-1) return ans[u];
    int cnt=Dev[u].In.size();
    vector<int>t;
    for(int i=0;i<cnt;++i){
        t.push_back(Input[s][Dev[u].In[i]]);
    }
    cnt=Dev[u].Out.size();
    for(int i=0;i<cnt;++i){
        t.push_back(dfs(s,Dev[u].Out[i]));
    }
    return ans[u]=Operation(t,Dev[u].opt);
}
bool topolog(int n){
    queue<int>Q;
    for(int i=1;i<=n;++i){
        if(!Ind[i]) Q.push(i);
    }
    int cnt=0;
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        ++cnt;
        int cnt=e[u].size();
        for(int i=0;i<cnt;++i){
            int v=e[u][i];
            if(!(--Ind[v])) Q.push(v);
        }
    }
    return cnt==n;
}
int main(){
    map<string,int>Mp;
    Mp["NOT"]=0;Mp["AND"]=1;Mp["OR"]=2;Mp["XOR"]=3;Mp["NAND"]=4;Mp["NOR"]=5;
    char str[10];
    int Q;scanf("%d",&Q);
    while(Q--){
        int m,n;scanf("%d%d",&m,&n);    //电路和器件数量
        for(int i=1;i<=n;++i){
            e[i].clear();
            Ind[i]=0;
            Dev[i].In.clear();
            Dev[i].Out.clear();
        }
        for(int i=1;i<=n;++i){   //每个器件
            scanf("%s",str);
            Dev[i].opt=Mp[str];
            int k;scanf("%d",&k);
            for(int j=0;j<k;++j){
                scanf("%s",str);
                int num=getNum(1,str);
                if(str[0]=='I') Dev[i].In.push_back(num);
                else{
                    e[num].push_back(i);
                    Ind[i]++;
                    Dev[i].Out.push_back(num);
                }
            }
        }
        int S;scanf("%d",&S);
        for(int i=0;i<S;++i){
            for(int j=1;j<=m;++j) scanf("%d",&Input[i][j]);
        }
        bool fg=topolog(n);
        if(!fg) puts("LOOP");
        for(int i=0;i<S;++i){
            int s,num;scanf("%d",&s);
            memset(ans,-1,sizeof(ans));
            for(int j=0;j<s;++j){
                scanf("%d",&num);
                if(fg) printf("%d%c",dfs(i,num),j==s-1?'\n':' ');
            }
        }
    }
    return 0;
}

星际旅行
密信与计数

2020-06⭐

markdown渲染器

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>323
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<limits>
/* CCF202006-3 Markdown渲染器 */
using namespace std;
string standard(string t)
{
    t.erase(0, t.find_first_not_of(' '));
    t.erase(t.find_last_not_of(' ') + 1);
    return t;
}

struct Markdown {
    int type;
    string s;
};
vector<Markdown> v;    // 1:新项目,2:子项目,3:段落

int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    bool flag = false;
    string s;
    int w;
    cin >> w;
    while (getline(cin, s)) {
        if ((int)s.size() == count(s.begin(), s.end(), ' ')) flag = true;
        else {
            if (flag || v.empty()) {
                if (s.size() >= 2 && s[0] == '*' && s[1] == ' ')
                    v.push_back({ 1, standard(s.substr(2)) });
                else
                    v.push_back({ 3, standard(s) });
                flag = false;
            }
            else {
                Markdown& last = v.back();
                if (last.type <= 2) {
                    if (s.size() >= 2 && s[0] == ' ' && s[1] == ' ')
                        last.s += " " + standard(s.substr(2));
                    else if (s.size() >= 2 && s[0] == '*' && s[1] == ' ')
                        v.push_back({ 2, standard(s.substr(2)) });
                    else
                        v.push_back({ 3, standard(s) });
                }
                else {
                    if (s.size() >= 2 && s[0] == '*' && s[1] == ' ')//新项目
                        v.push_back({ 1, standard(s.substr(2)) });
                    else
                        last.s += " " + standard(s);
                }
            }
        }
    }

    int ans = 0;
    for (int i = 0; i < (int)v.size(); i++) {
        string t = v[i].s;
        if (v[i].type != 2 && i > 0)
            ans++;
        if (v[i].type <= 2) {
            if (t.size() == 0) ans++;
            else {
                for (int i = 0; i < (int)t.size(); i += (w - 3)) {
                    while (i < (int)t.size() && t[i] == ' ') i++;
                    ans++;
                }
            }
        }
        else {
            for (int i = 0; i < (int)t.size(); i += w) {
                while (i < (int)t.size() && t[i] == ' ') i++;
                ans++;
            }
        }
    }

    cout << ans << endl;

    return 0;
}

1246

动态规划

乔乔和牛牛逛超市

2019-12

化学方程式

区块链

魔数

2019-09⭐

字符画

/* CCF201909-3 字符画 */

#include <bits/stdc++.h>

using namespace std;

const int N = 1080;
const int M = 1920;
struct RGB {
    int rgb[3];
} image[N][M];

bool isrgbeq(RGB &a, RGB &b)
{
    for (int i = 0; i < 3; i++)
        if (a.rgb[i] != b.rgb[i]) return false;
    return true;
}

void output(string t)
{
    for(int i = 0; t[i]; i++) // 转为ascii码
        cout << "\\x" << hex << uppercase << setw(2) << int(t[i]);
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    int m, n, p, q;
    cin >> m >> n >> p >> q;

    string rgb;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            cin >> rgb;
            if (rgb.size() == 2)
                rgb += string(5, rgb.back());   // #a变换为#aaaaaa
            else if (rgb.size() == 4)
                // #abc变换为#aabbcc
                rgb = "#" + string(2,rgb[1]) + string(2,rgb[2]) + string(2,rgb[3]);

            // 将16进制转换为10进制进行存储
            RGB color;
            for (int k = 0; k < 3; k++)
                color.rgb[k] = stoi(rgb.substr(2 * k + 1, 2), 0, 16);
            image[i][j] = color;
        }

    // 处理小块(计算平均值),输出小块
    RGB last = {0, 0, 0}, defcolor = {0, 0, 0};
    for (int i = 0; i < n / q; i++) {
        for (int j = 0; j < m / p; j++) {
            RGB cur = {0, 0, 0};
            for (int i2 = 0; i2 < q; i2++)
                for (int j2 = 0; j2 < p; j2++)
                    for (int k = 0; k < 3; k++)
                        cur.rgb[k] += image[i * q + i2][j * p + j2].rgb[k];
            // 计算平均值
            for (int k = 0; k < 3; k++)
                cur.rgb[k] /= p * q;

            if (isrgbeq(cur, last))   // 跟前一个小块一样
                ;
            else if (isrgbeq(cur, defcolor)) { // 跟默认一样
                last = defcolor;
                cout << "\\x1B\\x5B" << "\\x30\\x6D";
            } else {
                //如果都不一样
                last = cur;
                output("\x1b[48;2;" + to_string(cur.rgb[0]) + ";" + to_string(cur.rgb[1]) + ";" + to_string(cur.rgb[2]) + "m");
            }
            cout<<"\\x20";  // 每个小块结束输出一个空格
        }
        if (!isrgbeq(last, defcolor)) { // 换行判断结尾是否为默认值
            last = defcolor;
            cout << "\\x1B\\x5B" << "\\x30\\x6D";
        }
        cout << "\\x0A";    // 输出一个换行符
    }

    return 0;
}

/*
1 1
1 1
#010203

2 2
1 2
#111111
#0
#111
*/

推荐系统

城市规划

2019-03⭐

损坏的RAIDS

消息传递接口

317号子任务

2018-09

元素选择器

在这里插入图片描述

#include<iostream>
#include<vector>
#include<string>
#include<sstream>
using namespace std;

int n=0,m=0;
struct element{
	string label;   //标签
	int level;
	string id;   //属性 
};
element e[110];
vector<string> q(0);   //保存查询 
vector<int> ans(0);   //保存答案 

void toLower(string &t){   //转换为小写字母 
	for(int i=0;i<t.size();i++){
		if(t[i]>'A'-1&&t[i]<'Z'+1){
			t[i]=tolower(t[i]);
		}
	}
} 

void split(string &t,int x){
	int suo=0,flag=0;
	int s1=0,s2=0;
	for(int i=0;i<t.size();i++){
		if(t[i]=='.'){suo++;	}
		if(t[i]!='.'&&flag==0){   //记录遇到的第一个非'.'位置 
			flag=1;	 s1=i;
		}
		if(t[i]==' '&&flag==1){   //若有属性,记录属性出现位置
			s2=i+1;	flag=2;	break; 
		}
	}
	string tmp,tmp_id;
	if(flag!=2){   //没有属性,只有标签和缩进 
		tmp=t.substr(s1);
		toLower(tmp);   //标签大小写不敏感,变为小写
		e[x].label=tmp;
		e[x].level=suo/2; 
	}
	else{   //有属性 
		tmp=t.substr(s1,s2-s1-1);
		toLower(tmp);   //标签大小写不敏感,变为小写
		tmp_id=t.substr(s2);
		e[x].label=tmp;
		e[x].id=tmp_id;
		e[x].level=suo/2; 
	}
} 

bool match(int x){   //判断元素是否真的与选择器匹配(主要是看祖先) 
	int t=e[x].level,qq=q.size()-2;
	for(int i=x-1;i>=0;i--){
		if(e[i].level==t-1){
			if(q[qq][0]!='#'&&q[qq]==e[i].label){qq--;}
            else if(q[qq][0]=='#'&&q[qq]==e[i].id){qq--;}
            t=e[i].level;
            if(qq<0)return true;
		}
	}
	return false;
}

int main(){
	cin>>n>>m;
	string tmp;
	getchar();   //吃掉换行符
	for(int i=0;i<n;i++){   //读入结构化文档 
		getline(cin,tmp);
		split(tmp,i);
	} 
	
	for(int i=0;i<m;i++){   //读入选择器 
		getline(cin,tmp);
		stringstream st;
		st<<tmp;
		string tt;
		while(st>>tt){
			if(tt[0]!='#'){toLower(tt);	}   //不是id选择器,大小写不敏感 
			q.push_back(tt);
		}
		int qs=q.size();
		for(int j=0;j<n;j++){
			if(q[qs-1][0]=='#'&&q[qs-1]==e[j].id
			||q[qs-1][0]!='#'&&q[qs-1]==e[j].label){
				if(q.size()==1||match(j)){
					ans.push_back(j+1);
				}
			}
		}
		cout<<ans.size();
		for(int i=0;i<ans.size();i++){
			cout<<" "<<ans[i];
		}
		cout<<"\n";
		ans.clear();
		q.clear();
	}
	return 0;
} 

再卖菜

在这里插入图片描述

#include <iostream>
using namespace std;
 
int n;
int first[301];     // 第一天的菜价
int second[301];    // 第二天的菜价
bool visit[301][201][301];  // visit[x][cur][pre]:第x个商家的菜价为cur,第x-1个商家的菜价为pre的情况已经遍历过了
 
/* 第d个卖家取值为val */
bool dfs(int d, int val)
{
    // 记忆化搜索
    if (visit[d][val][first[d - 1]]) return false;   // 剪枝:若搜过,则说明这个分支不行,直接剪掉
    visit[d][val][first[d - 1]] = true;   // 记忆:记录这种情况已经被搜索过了
 
    if (val <= 0) return false;     // val的合法性
    first[d] = val;
 
    // first[1] = val时,根据second[1]求出first[2]的可能取值
    if (d == 1)
    {
        int temp = second[1] * 2;
        // 注意||的短路性质:左边的为true时右边将不会进行递归
        return dfs(2, temp - first[1]) || dfs(2, temp - first[1] + 1);
    }
    // d ∈ [2, n]时
    else if (d <= n)
    {
        int temp = second[d] * 3;
        return dfs(d + 1, temp - first[d - 1] - first[d]) ||
               dfs(d + 1, temp - first[d - 1] - first[d] + 1) ||
               dfs(d + 1, temp - first[d - 1] - first[d] + 2);
    }
    // 当完成第n个商家的赋值时,需要检查second[n]是否匹配
    else return (first[n - 1] + first[n]) / 2 == second[n];
}
 
int main()
{
    // 关闭同步
    ios::sync_with_stdio(false);
 
    // 输入
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> second[i];
 
    // 考察第一个商家的可能取值为[1, 2*second[1]]
    for (int i = 1; i <= 2 * second[1]; ++i)
    {
        bool flag = dfs(1, i);
        if (flag == true) break;
    }
 
    // 输出结果
    cout << first[1];
    for (int i = 2; i <= n; ++i)
        cout << ' ' << first[i];
    return 0;
}

线性递推式

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值