2016-2017 ACM-ICPC, NEERC, Moscow Subregional Contest(补题中)
加粗:赛时AC
普通:赛后AC
Problem A. Altitude
思路:由题意,必定会出现答案为2的位置,枚举每一个点,找到符合题意的输出。
Problem B. Blocking Buffer
思路:由题意存在一个锁死区间(l-w,r),易知r和w的最大公因数的倍数都能到达,查找是否有最大公因数的倍数在这个区间即可。
Problem E. Economy Printing
思路:设dp(i,j,k)表示第i个,前一个选择j方案,当前选择k方案时的最小长度。记录每次转移的操作最后输出即可。
这题做的时候没有完成,很多细节还是很难想清楚的,而且码力也不够,总是出些低级错误。
#include<iostream> #include<cstdio> #include<string> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #include<algorithm> #include<queue> #define N 300100 #define ll long long using namespace std; ll n; ll dp[N][5][5]; ll las[N][5][5]; ll a[N],op[N]; queue<ll> qji,qou,qlian,qsig; const ll MAXX=10000000000; //快读 inline void read(ll &p) { p=0; ll f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') p=p*10+(ch-'0'),ch=getchar(); p*=f; } inline ll minn(ll x,ll y,ll z) { ll Minn=MAXX; for(ll j=1;j<=4;j++) { if(Minn>dp[x][j][y]) { Minn=dp[x][j][y]; las[x+1][y][z]=j; } } return Minn; } inline ll dig(ll limx) { ll x=a[limx]; ll anss=0; while(x) { anss++; x/=10; } return anss; } inline ll jud(ll limx,ll limy) { return dig(limx)-dig(limy); } int main() { read(n); for(int i=1;i<=n;i++) read(a[i]); sort(a+1,a+1+n); a[0]=MAXX; memset(dp,0x3f3f3f,sizeof(dp)); dp[1][1][1]=dig(1)+1;dp[1][1][2]=2*(dig(1)+1); if(a[1]%2==0) dp[1][1][4]=2*(dig(1)+1); else dp[1][1][3]=2*(dig(1)+1); for(int i=2;i<=n;i++) { for(int j=1;j<=4;j++) { for(int k=1;k<=4;k++) { if(k==2) { if(j==2) { if(a[i]==a[i-1]+1) dp[i][j][k]=minn(i-1,j,k)+jud(i,i-1); else dp[i][j][k]=minn(i-1,j,k)+2*(dig(i)+1); } else dp[i][j][k]=minn(i-1,j,k)+2*(dig(i)+1); } if(k==1) dp[i][j][k]=minn(i-1,j,k)+dig(i)+1; if(k==3) { if(a[i]%2==0) dp[i][j][k]=MAXX; else { if(j==3) { if(a[i]==a[i-1]+2) dp[i][j][k]=minn(i-1,j,k)+jud(i,i-1); else dp[i][j][k]=minn(i-1,j,k)+2*(dig(i)+1); } else { if(a[i]==a[i-2]+2) { dp[i][j][k]=dp[i-1][3][j]+jud(i,i-2); las[i][j][k]=3; } else dp[i][j][k]=minn(i-1,j,k)+2*(dig(i)+1); } } } if(k==4) { if(a[i]%2==1) dp[i][j][k]=MAXX; else { if(j==4) //合并 { if(a[i]==a[i-1]+2) dp[i][j][k]=minn(i-1,j,k)+jud(i,i-1); else dp[i][j][k]=minn(i-1,j,k)+2*(dig(i)+1); } else { if(a[i]==a[i-2]+2) { dp[i][j][k]=dp[i-1][4][j]+jud(i,i-2); las[i][j][k]=4; } else dp[i][j][k]=minn(i-1,j,k)+2*(dig(i)+1); } } } } } } ll ans=MAXX; ll pos=-1,lasop2=-1,lasop1=-1; for(int i=1;i<=4;i++) { for(int j=1;j<=4;j++) { if(dp[n][i][j]<ans) { op[n]=j; lasop2=las[n][i][j]; lasop1=i; ans=dp[n][i][j]; } } } for(int i=n-1;i>=1;i--) { ll limm=las[i][lasop2][lasop1]; op[i]=lasop1; lasop1=lasop2; lasop2=limm; } for(int i=1;i<=n;i++) { if(op[i]==3) qji.push(a[i]); if(op[i]==4) qou.push(a[i]); if(op[i]==1) qsig.push(a[i]); if(op[i]==2) qlian.push(a[i]); } bool flag=0; while(!qsig.empty()) { if(!flag) printf("%lld",qsig.front()),qsig.pop(),flag=1; else printf(",%lld",qsig.front()),qsig.pop(); } ll head=-1,tail=-1; bool df=1; while(!qji.empty()) { df=0; if(head==-1) { head=tail=qji.front(); qji.pop(); } else if(qji.front()==tail+2) { tail+=2; qji.pop(); } else { if(!flag) printf("%lld#%lld",head,tail),flag=1; else printf(",%lld#%lld",head,tail); head=tail=-1; } } if(!df) { if(!flag) printf("%lld#%lld",head,tail),flag=1; else printf(",%lld#%lld",head,tail); head=tail=-1; df=1; } while(!qou.empty()) { df=0; if(head==-1) { head=tail=qou.front(); qou.pop(); } else if(qou.front()==tail+2) { tail+=2; qou.pop(); } else { if(!flag) printf("%lld%c%lld",head,'%',tail),flag=1; else printf(",%lld%c%lld",head,'%',tail); head=tail=-1; } } if(!df) { if(!flag) printf("%lld%c%lld",head,'%',tail),flag=1; else printf(",%lld%c%lld",head,'%',tail); head=tail=-1; df=1; } while(!qlian.empty()) { df=0; if(head==-1) { head=tail=qlian.front(); qlian.pop(); } else if(qlian.front()==tail+1) { tail++; qlian.pop(); } else { if(!flag) printf("%lld-%lld",head,tail),flag=1; else printf(",%lld-%lld",head,tail); head=tail=-1; } } if(!df) { if(!flag) printf("%lld-%lld",head,tail),flag=1; else printf(",%lld-%lld",head,tail); head=tail=-1; df=1; } return 0; }
Problem F. Format
思路:这题是杰哥做的,总的就是模拟,注意所有有效字符都包含和所有有效字符都没有的时候的答案要特判。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <array> #include <vector> #include <map> #include <unordered_map> #include <set> #include <unordered_set> #include <stack> #include <queue> #include <bitset> #include <algorithm> #include <numeric> #include <functional> #include <cmath> using namespace std; typedef long long ll; #define finc(i,a,b) for(int i=(int)(a);i<(int)(b);i++) #define fdec(i,a,b) for(int i=(int)(b);i-->(int)(a);) #define reset(a,...) a=decltype(a)(__VA_ARGS__) #define endl '\n' #define endb ' ' #define read(a,str) scanf("%"#str,&a) #define print(a,str) printf("%"#str,a) void ac() { bitset<255> note, qaq; string str; getline(cin, str); finc(i, 0, str.size()) note[str[i]] = 1; auto f = [](const bitset<255>& note)->string { auto g = [¬e](char begin, char end) { string ret; finc(i, begin, end + 1) { if (note[i]) if (note[i - 1]) ret.back() = i; else ret.push_back(i), ret.push_back(i); } return ret; }; string ret; ret += g(' ', ' '), ret += g('0', '9'); ret += g('A', 'Z'), ret += g('a', 'z'); finc(i, 0, ret.size() - 1) if ( (ret[i] == ' ' && ret[i + 1] == '0') || (ret[i] == '9' && ret[i + 1] == 'A') || (ret[i] == 'Z' && ret[i + 1] == 'a') ) ret[i] = ret[i + 1] = 0; string ans; finc(i, 0, ret.size()) if (ret[i]) ans.push_back(ret[i]); ret.clear(); auto mul = [](char c) { if (c == '0') return ' '; if (c == 'A') return '9'; if (c == 'a') return 'Z'; return (char)(c - 1); }; for (int i = 1; i < ans.size(); i += 2) if (ans[i] == ans[i - 1]) ret.push_back(ans[i]); else if (mul(ans[i]) == ans[i - 1]) ret.push_back(ans[i - 1]), ret.push_back(ans[i]); else ret.push_back(ans[i - 1]), ret.push_back('-'), ret.push_back(ans[i]); finc(i, 0, ret.size() - 1) { if (ret[i + 1] == '-') { if (ret[i] == '0') ret[i] = '!'; if (ret[i] == 'A') ret[i] = ':'; if (ret[i] == 'a') ret[i] = '['; } } return ret; }; auto g = [&qaq, ¬e](char a, char b) { finc(i, a, b + 1) qaq[i] = ~note[i]; }; g(' ', ' '), g('0', '9'); g('A', 'Z'), g('a', 'z'); auto x = f(note), y = "^" + f(qaq); string ans; if (x.size() != y.size()) if (x.size() < y.size()) ans = x; else ans = y; else ans = min(x, y); if (ans == "^") cout << "%[" << ans << "!]" << endl; else cout << "%[" << ans << "]" << endl; } int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int test = 1; //cin >> test; while (test--) ac(); return 0; }
Problem G. Great Guest Gathering
思路:模拟就行了,只要步骤有效,怎么做都行。
Problem K. Knights of the Old Republic
思路:这题是壕哥做的,用kruscal从小到大一个一个加边,边两边的点的集合做合并时,结果是两边的和(不选这条边)以及两边的最大人数*最小值(选这条边),注意题目给的图不一定连通
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define ll long long const int N=3e5+10; int fa[N]; ll maxx[N],minn[N],dp[N],a[N],b[N]; struct node { int x,y,w; }mp[N]; bool cmp(node a,node b) { return a.w<b.w; } int findd(int x) { if (x==fa[x]) return x; else return fa[x]=findd(fa[x]); } int main() { int n,m,i; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) { scanf("%lld%lld",&a[i],&b[i]); maxx[i]=a[i],minn[i]=b[i],dp[i]=a[i]*b[i],fa[i]=i; } for (i=1;i<=m;i++) scanf("%d%d%d",&mp[i].x,&mp[i].y,&mp[i].w); sort(mp+1,mp+1+m,cmp); for (i=1;i<=m;i++) { int x=findd(mp[i].x),y=findd(mp[i].y); if (x==y) continue; maxx[x]=maxx[y]=max(max(maxx[x],maxx[y]),1ll*mp[i].w); minn[x]=minn[y]=min(minn[x],minn[y]); dp[x]=dp[y]=min(dp[x]+dp[y],maxx[x]*minn[y]); fa[x]=y; } ll ans=0; for (i=1;i<=n;i++) if (fa[i]==i) ans+=dp[i]; printf("%lld\n",ans); return 0; } /* 3 1 100 1 100 3 10 2 2 3 12 */
Problem L. Lazy Coordinator
思路:这题是杰哥做的,据说是一道概率题,一向数学弃疗的我就没有看这题。