題目鏈接: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~