题目链接:https://ac.nowcoder.com/acm/contest/4462
最近沉迷于写Minecraft的mod,好久没写题了,拿了结束好几天的这场练练手,好自闭哇~ AB都没写出来 只写了D - H 和J 共六题…状态极其不好
截至目前,除了没有I题工具人的题解,本套其他题均有~
我的程序头
为了节省篇幅(代码复用嘛)233
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rr(x,y) read(x);read(y)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define pb(x) push_back(x)
#define sss(str) scanf("%s",str+1)
#define ssf(x) scanf("%lf",&x)
#define all(x) x.begin(),x.end()
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef double dd;
typedef pair<LL,LL> pt;
const int N=1e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const int sz=18;
const double eps=1e-10;
const double pi=acos(-1);
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
A 操作序列
这题我比赛时想的好复杂,各种数据结构,都没写出了。看题解才知道 就是个简单的STL运用…
把不为0的全部用map记录下来(map自动离散化了,懒人必备 )
①:增加,先二分找到map的的左右区间 然后有的话说明 不用加,没有的话就加呗
②:如果map不为空,那map的第一个元素去掉就行了
③:找得到输出找到的,找不到输出0
完事了…
//***********************
LL n;
map<int,int> m;
//***********************
int main()
{
r(n);
FOR(i,1,n){
int a;
scanf("%d",&a);
char c=getchar();
if(a==-1){
if(m.begin()==m.end()){
cout<<"skipped\n";
}
else{
cout<<(m.begin())->second<<endl;
m.erase(m.begin());
}
}
else if(c=='\n'){
if(m.count(a)) cout<<m[a]<<endl;
else cout<<0<<endl;
}
else if(c==' '){
int b; r(b);
bool flag=1;
map<int,int>::iterator it;
for(it=m.lower_bound(a-30);it!=m.upper_bound(a+30);it++){
flag=0;
break;
}
if(flag){
if(m.count(a)) m[a]+=b;
else m[a]=b;
}
}
}
return 0;
}
B 树上子链
我们从一个点出发,记录它往下dfs的最长链和次长链,最长链+次长链+它本身就是包含它的最长链,如果不包含就往上返回嘛(返回这个节点+最长链,注意没有次长链)
//***********************
LL n,m;
struct edge
{
int to,next;
}e[N<<1];
int head[N],f[N];
int cnt;
LL ans;
//***********************
void add_edge(int a,int b)
{
e[++cnt].to=b;
e[cnt].next=head[a];
head[a]=cnt;
}
LL dfs(int x,int fa)
{
//cout<<x<<endl;
LL max1=0,max2=0;
for(int i=head[x];i;i=e[i].next){
int y=e[i].to;
if(y!=fa){
LL tmp=dfs(y,x);
if(tmp>max1){
max2=max1;
max1=tmp;
}
else if(tmp>max2) max2=tmp;
}
}
ans=max(ans,max1+max2+f[x]);
return max1+f[x];
}
int main()
{
r(n);
FOR(i,1,n) r(f[i]);
cnt=0;
FOR(i,1,n-1){
int a,b;
rr(a,b);
add_edge(a,b);
add_edge(b,a);
}
ans=-6e18;
dfs(1,-1);
cout<<ans<<endl;
return 0;
}
C 交换游戏
我貌似没有仔细想这题,题目都看错了,我以为有N个孔(1e5),虽然不看错可能也不会
每个孔就2种状态,记为0和1,,12个孔就212=4096种,我们记忆化搜索记录前一个状态的值的话 那它这么多询问也是O(1)解决了 然后找到转移的共性 3个相邻的孔 中间为1,两边异或为1 转移即与7异或(111)
//***********************
LL n,m;
char s[20];
int f[N];
//***********************
int dfs(int x)
{
if(f[x]|| !x) return f[x];
int cnt=0;
FOR(i,0,11){
if((1<<i)&x) cnt++;
}
FOR(i,0,9){
if(((x>>i+1)&1)&&((x>>i+2)&1)^((x>>i)&1)){
cnt=min(cnt,dfs(x^(7<<i)));
}
}
return f[x]=cnt;
}
int main()
{
r(n);
f[0]=0;
FOR(i,1,n){
scanf("%s",s);
int res=0;
FOR(i,0,11){
if(s[i]=='o') res+=(1<<i);
}
cout<<dfs(res)<<endl;
}
return 0;
}
D 收集纸片
好像是那啥状压dp解决TSP问题?半年前写的 不太记得了,但是瞎写就AC了~~(也不知道有没有漏洞,我是dp蒟蒻)~~
一看到10个纸片就想到了状压,就是转移的问题,我们令dp[ i ][ j ]为 现在状态为i 端点为j的最小距离 ,怎么理解状态i呢?就是把它看成二进制数,有几个1,那个1位置对应的点就是已经走到了的
//***********************
int n,m;
char str[N];
int dp[1<<sz][sz];
int a[sz],b[sz];
int dis[sz][sz];
//***********************
int main()
{
int t;r(t);
while(t--){
r(n); r(m);
int st,se,k;
rrr(st,se,k);
FOR(i,1,k){
rr(a[i],b[i]);
}
FOR(i,1,k){
FOR(j,1,k){
dis[i][j]=abs(a[i]-a[j])+abs(b[i]-b[j]);
}
}
memset(dp,127/3,sizeof dp);
FOR(i,1,k){
dp[1<<i-1][i]=abs(a[i]-st)+abs(b[i]-se);
}
FOR(i,1,(1<<k)-1){
FOR(j,1,k){
int t=1<<j-1;
if(t&i){
FOR(l,1,k){
if(l==j||((1<<l-1)&i)==0) continue;
dp[i][j]=min(dp[i][j],dp[i^t][l]+dis[j][l]);
}
}
}
}
int ans=INF;
FOR(i,1,k){
ans=min(ans,dp[(1<<k)-1][i]+abs(a[i]-st)+abs(b[i]-se));
}
cout<<"The shortest path has length "<<ans<<endl;
}
return 0;
}
E 方块涂色
水题
//***********************
int n,m;
char str[N];
//***********************
int main()
{
int a,b;
while(~scanf("%d%d%d%d",&n,&m,&a,&b)){
cout<<1ll*(n-a)*(m-b)<<endl;
}
return 0;
}
F 累乘数字
水题
//***********************
LL n,m;
//***********************
int main()
{
while(~scanf("%d%d",&n,&m)){
cout<<n;
FOR(i,1,m) cout<<"00";
cout<<endl;
}
return 0;
}
G 仓库选址
这题有点意思,我的思路是考虑点之间的转移
假如我们现在选定了点(1,1)为仓库,那么求出以这个点为仓库的答案是1e4,然后假如我们现在改成点(1,2)那这个答案会怎么改变? 答案加上1那一列的数字和,然后减去2到m列的数字和 这个是不是可以通过记录前缀和O(1)搞定? 同理(2,1)也是很好解决的~
//***********************
int n,m;
int f[M][M];
int sum[M][M];
//***********************
int main()
{
int t;
r(t);
while(t--){
rr(n,m);
swap(n,m);
FOR(i,1,n){
FOR(j,1,m){
r(f[i][j]);
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+f[i][j];
}
}
int res=0;
FOR(i,1,n){
FOR(j,1,m){
res+=(i+j-2)*f[i][j];
}
}
// FOR(i,1,n){
// FOR(j,1,m) cout<<sum[i][j]<<' ';
// cout<<endl;
// }
int ans=res,now=res;
FOR(i,1,n){
int tmp=now;
ans=min(ans,tmp);
FOR(j,1,m){
tmp+=sum[n][j]-(sum[n][m]-sum[n][j]);
ans=min(ans,tmp);
}
now+=sum[i][m]-(sum[n][m]-sum[i][m]);
}
cout<<ans<<endl;
}
return 0;
}
H 货物种类
我的做法是把相同的货物的操作能合并的先合并,然后就不会出现重复给相同货物的情况了。最后差分~
//***********************
int n,m;
struct node
{
int l,r,v;
bool operator<(node a)
{
if(v==a.v&&l==a.l) return r<a.r;
if(v==a.v) return l<a.l;
return v<a.v;
}
node(){};
node(int ll,int rr,int vv){
l=ll; r=rr; v=vv;
}
}f[N],g[N];
int sum[N];
//***********************
int main()
{
rr(n,m);
FOR(i,1,m){
rrr(f[i].l,f[i].r,f[i].v);
}
sort(f+1,f+m+1);
int cnt=0,l=f[1].l,r=f[1].r;
FOR(i,2,m+1){
if(f[i].v==f[i-1].v){
if(f[i].l<=r){
r=max(r,f[i].r);
}
else{
sum[l]++; sum[r+1]--;
l=f[i].l; r=f[i].r;
}
}
else{
sum[l]++; sum[r+1]--;
l=f[i].l; r=f[i].r;
}
}
int ans=0,maxx=0,now=0;
FOR(i,1,n){
now+=sum[i];
if(now>maxx){
maxx=now;
ans=i;
}
// cout<<now<<endl;
}
cout<<ans<<endl;
return 0;
}
I 工具人
J 计算A+B
我开的第一题,看到A+B就觉得好写。然后被搞心态了…
大模拟,不用多解释吧…
//***********************
LL n,m;
char str[N];
int s1[N],s2[N];
//***********************
bool check(int l,int r)
{
//cout<<l<<' '<<r<<endl;
if(l>r) return 0;
if(str[l]=='0'&&l!=r){
return 0;
}
return 1;
}
int main()
{
int t;
r(t);
while(t--){
scanf("%s",str+1);
int len=strlen(str+1);
int mid=0,num=0;
bool flag=1;
FOR(i,1,len){
if(str[i]=='+'){
num++;
mid=i;
}
if(str[i]!='+'&&str[i]<'0'&&str[i]>'9'){
flag=0;
break;
}
}
if(num!=1||!flag){
cout<<"skipped\n";
continue;
}
if(check(1,mid-1)==0||check(mid+1,len)==0){
cout<<"skipped\n";
continue;
}
memset(s1,0,sizeof s1);
memset(s2,0,sizeof s2);
for(int i=mid-1;i>=1;i--) s1[mid-i]=str[i]-'0';
for(int i=len;i>=mid+1;i--) s2[len-i+1]=str[i]-'0';
int n=mid-1,m=len-mid;
FOR(i,1,max(n,m)){
s1[i]+=s2[i];
int pos=i;
while(s1[pos]>=10){
s1[pos+1]++;
s1[pos]-=10;
pos++;
}
}
int lst=0;
for(int i=1e4+50;i>=1;i--){
if(s1[i]!=0){
lst=i; break;
}
}
if(lst==0) cout<<0;
for(int i=lst;i>=1;i--) cout<<s1[i];
cout<<endl;
}
return 0;
}
end~