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;
}