T1
[贪心]
按照等待时间排序,然后记录最大不满意度即可。->复杂度正确O(nlogn),正确性未知。
可以考虑跟全排列的暴力拍一拍。数据好造。暴力好写。
再想5分钟O(n^2)的做法->想不出来。
一遍过小样例和大样例。突然不想拍。写完后面的题再拍。。
今日rank1选手被这题卡了ak哈哈哈。。
【code】
#includeusing namespace std; #define ll long long #define File "transact" inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline int read(){ int x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();} return x*f; } const int mxn = 1e5 + 5; int n; struct P{ int t,d; }p[mxn]; inline bool cmp(P t1,P t2){ return t1.d < t2.d; } int main(){ file(); n = read(); for(int i = 1;i <= n; ++i) p[i].t = read(); for(int i = 1;i <= n; ++i) p[i].d = read(); sort(p+1,p+n+1,cmp); ll s(0),mx(0); for(int i = 1;i <= n; ++i){ s += (ll)p[i].t; if(s > (ll)p[i].d) mx = max(mx,s-(ll)p[i].d); } printf("%lld\n",mx); return 0; }
T2
[拓扑?]
由于每个人接到球之后会把球传给谁是固定的,并且传球的距离也是固定的。
改变接球顺序来改变传球接力最长距离,就只是改变第一个发球人的顺序。
当球要传给一个已经拿到过球的人时,传球停止。
O(n^2)暴力 -> 50pts
可以想到这个图实际上是一棵树(有向)多一条边,要求该图的直径。
一个正确性靠谱但复杂度没了的做法。从每一个入度为零的点出发。
一个复杂度正确正确性未知的做法。建双向边,特殊处理,跑树的直径即可。
那就冷静一下之后写这两个程序。
然后正确性未知的做法果然是个垃圾。
想到实际上就是要处理一个环加上若干枝。
且必定从某个入度为零的点进入遍历。
这个环(少一条边)是无论如何都要遍历一遍的。
枚举断点,取max即可。
【code】
#includeusing namespace std; #define ll long long #define File "pass" inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline int read(){ int x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();} return x*f; } const int mxn = 5e5 + 5; int n; int in[mxn],cir[mxn]; ll a[mxn],d[mxn],b[mxn],f[mxn]; queue<int> q; bool v[mxn]; ll tot(0),sum(0),ans(0); int main(){ file(); n = read(); for(int i = 1;i <= n; ++i){ a[i] = read(),d[i] = read(); in[a[i]]++; } for(int i = 1;i <= n; ++i) if(!in[i]) q.push(i); while(!q.empty()){ ll x = q.front(); q.pop(); ll y = a[x]; f[y] = max(f[y],f[x] + d[x]); if(!(--in[y])) q.push(y); } for(int i = 1;i <= n; ++i){ if(in[i] && !v[i]){ ll k = a[i]; cir[++tot] = i; b[a[i]] = d[i]; sum = d[i]; while(k != i){ v[k] = 1; cir[++tot] = k; b[a[k]] = d[k]; sum += d[k]; k = a[k]; }//环 for(int j = 1;j <= tot; ++j) ans = max(ans,sum + f[cir[j]] - b[cir[j]]); } } printf("%lld\n",ans); return 0; } /* 5 2 1 3 2 4 1 2 3 3 3 */
T3
[dp]
考虑最暴力的暴力。
选择在哪一个方格开始游戏O(n^2)
向哪个方向走多少各O(4*n)
走到当前格子之后继续走。。
再次O(4*n)枚举
总共枚举T次。
总复杂度为O(n^2*4^T*n^T) -> 30pts
等哈。这莫不是个dp嘛。
然后就可以满分了。。
【code】
#includeusing namespace std; #define ll long long #define File "coin" inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline ll read(){ ll x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();} return x*f; } const int mxn = 30; const int mxT = 105; const int mxW = 155; int n,C,W,T; int dx[5] = {-1,1,0,0,0},dy[5] = {0,0,-1,1,0}; inline ll min_(ll x,ll y){ return x < y ? x : y; } inline ll max_(ll x,ll y){ return x > y ? x : y; } inline bool ok(int x,int y){ if(x > 0 && x <= n && y > 0 && y <= n) return true; return false; } inline int x_(int i,int x,int c){ if(!c) return x+dx[i]; return x+2*c*dx[i]; } inline int y_(int i,int y,int c){ if(!c) return y+dy[i]; return y+2*c*dy[i]; } ll f[mxT][mxn][mxn][mxW]; ll a[mxn][mxn]; ll ans(0); int main(){ file(); n = read(),C = min_(n/2,read()),W = read(),T = read(); ///* memset(f,0xcf,sizeof f); for(int i = 1;i <= n; ++i) for(int j = 1;j <= n; ++j) f[0][i][j][0] = 0; for(int t = 1;t <= T; ++t){ for(int i = 1;i <= n; ++i) for(int j = 1;j <= n; ++j) a[i][j] = read(); for(int x = 1;x <= n; ++x) for(int y = 1;y <= n; ++y) for(int s = 0;s <= W; ++s) for(int i = 0;i < 5; ++i) for(int c = 0;c <= min_(C,s) && ok(x_(i,x,c),y_(i,y,c)) && (i!=4||!c); ++c) f[t][x][y][s] = max_(f[t][x][y][s],f[t-1][x_(i,x,c)][y_(i,y,c)][s-c] + a[x][y]); } for(int i = 1;i <= n; ++i) for(int j = 1;j <= n; ++j) for(int k = 0;k <= W; ++k) ans = max_(ans,f[T][i][j][k]); printf("%lld\n",ans); return 0; }