文章目录
- A - Signed Difficulty
- B - Same Name
- C - Many Balls
- D - Pair of Balls
- E - Amusement Park
- F - Max Sum Counting
- G - 01Sequence
比赛链接
A - Signed Difficulty
签到题
#include <cstdio>
int x, y;
char c;
int main() {scanf( "%d%c%d", &x, &c, &y );if( y <= 2 ) printf( "%d-", x );else if( y >= 7 ) printf( "%d+", x );else printf("%d", x );return 0;
}
B - Same Name
签到题
#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
map < pair < string, string >, int > mp;
int n;int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) {string a, b;cin >> a >> b;if( mp[make_pair( a, b )] ) return ! printf( "Yes\n" );mp[make_pair( a, b )] = 1;}printf( "No\n" );return 0;
}
C - Many Balls
简单题
发现是快速幂的逆过程
#include <cstdio>
#include <vector>
using namespace std;
#define int long long
vector < int > ans;
int n;signed main() {scanf( "%lld", &n );while( n ) {if( n & 1 ) ans.push_back( 0 );ans.push_back( 1 );n >>= 1;}for( int i = ans.size() - 1;~ i;i -- )printf( "%c", ans[i] + 'A' );return 0;
}
D - Pair of Balls
超难题!!!靠
不搞环,硬汉就搞大模拟
记录颜色两次出现位置,并带上标记,成为堆顶为000,在下面为111
当颜色两个位置都入队(成为其所在堆的堆顶)
弹出,并把堆下面一个元素标记为新的堆顶
就这么模拟,凸(艹皿艹 )
之前打的什么鬼傻逼set
/map
半天模拟不动,又TLE
又RE
又WA
o(╥﹏╥)o _(¦3」∠)_ ┏┛墓┗┓…(((m-__-)m
#include <cstdio>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
#define maxn 200005
struct node {int color, i, rnk, pos;node(){}node( int C, int I, int R, int P ) {color = C, i = I, rnk = R, pos = P;}
}c[maxn][2];
int n, m, cnt;
queue < node > q;
vector < int > g[maxn];
bool vis[maxn][2];int main() {scanf( "%d %d", &n, &m );for( int i = 1, k, x;i <= m;i ++ ) {scanf( "%d", &k );for( int j = 1;j <= k;j ++ ) {scanf( "%d", &x );g[i].push_back( x );if( ! vis[x][0] ) c[x][0] = node( x, i, j, 1 ), vis[x][0] = 1;else c[x][1] = node( x, i, j, 1 ), vis[x][1] = 1;}}for( int i = 1;i <= n;i ++ ) {auto ls = c[i][0];auto rs = c[i][1];vis[i][0] = vis[i][1] = 0;if( ! ls.pos and ! rs.pos ) {q.push( c[i][0] );q.push( c[i][1] );}}while( ! q.empty() ) {auto ls = q.front(); q.pop();auto rs = q.front(); q.pop();cnt ++;int nxt;if( ls.rnk ^ g[ls.i].size() ) {nxt = g[ls.i][ls.rnk];if( c[nxt][0].i == ls.i ) c[nxt][0].pos = 0;else c[nxt][1].pos = 0;if( ! c[nxt][0].pos and ! c[nxt][1].pos ) {q.push( c[nxt][0] );q.push( c[nxt][1] );}}if( rs.rnk ^ g[rs.i].size() ) {nxt = g[rs.i][rs.rnk];if( c[nxt][0].i == rs.i ) c[nxt][0].pos = 0;else c[nxt][1].pos = 0;if( ! c[nxt][0].pos and ! c[nxt][1].pos ) {q.push( c[nxt][0] );q.push( c[nxt][1] );}}}if( cnt ^ n ) printf( "No\n" );else printf( "Yes\n" );return 0;
}
E - Amusement Park
简单题
数学直接算
从大到小取,每次a[i]a[i]a[i]取到a[i+1]a[i+1]a[i+1]相同值就停,等差数列算这中间的值和
随着iii的枚举,前面全是相同的a[i]a[i]a[i],所以这等差数列算了后还要乘以一个iii的系数
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
#define maxn 100005
int n, k;
int a[maxn];signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ )scanf( "%lld", &a[i] );sort( a + 1, a + n + 1, []( int x, int y ) { return x > y; } );int ans = 0;for( int i = 1;i <= n;i ++ ) {int x = a[i] - a[i + 1];int sum = ( a[i] + a[i + 1] + 1 ) * x / 2;if( k <= x * i ) {x = k / i;sum = ( a[i] + a[i] - x + 1 ) * x / 2;ans += sum * i;a[i] -= k / i;k %= i;ans += a[i] * k;break;}else {ans += sum * i;k -= x * i;}}printf( "%lld\n", ans );return 0;
}
F - Max Sum Counting
简单题
凸(艹皿艹 ),傻逼背包倒DP调nm半个小时
按AAA排序,枚举AiA_iAi作为最大值
接下来就是选一些数满足BjB_jBj的和不超过AiA_iAi
设dpj:dp_j:dpj: 和为jjj的方案数
每次统计答案后,再转移iii的BiB_iBi的贡献
发现其实就是个简单背包
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
#define mod 998244353
#define maxn 5005
struct node { int a, b; }g[maxn];
int n;
int t[maxn], dp[maxn];bool cmp( node x, node y ) {return x.a < y.a;
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &g[i].a );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &g[i].b );sort( g + 1, g + n + 1, cmp );int ans = 0;dp[0] = 1;for( int i = 1;i <= n;i ++ ) {for( int j = 0;j <= g[i].a - g[i].b;j ++ )ans = ( ans + dp[j] ) % mod;for( int j = maxn - 1;j >= g[i].b;j -- )dp[j] = ( dp[j] + dp[j - g[i].b] ) % mod;}printf( "%lld\n", ans );return 0;
}
G - 01Sequence
看完题目是非常板的差分约束题面感
设sis_isi表示1−i1-i1−i中1
的个数
[l,r][l,r][l,r]区间内1
个数不少于xxx个,翻译约束为sr−sl−1≥xs_r-s_{l-1}\ge xsr−sl−1≥x
为了契合差分约束的≤\le≤
重新定义sis_isi表示1−i1-i1−i中0
的个数
翻译约束为sr−sl−1≤r−l+1−xs_r-s_{l-1}\le r-l+1-xsr−sl−1≤r−l+1−x
转化到图论上,连边l−1→rl-1\rightarrow rl−1→r有向边的边权r−l+1−xr-l+1-xr−l+1−x
跑最短路即可
本题卡SPFA
差分约束
为什么是≤\le≤约束(不等式左边为“点”,不等式右边为固定限制)
- 首先最长路目前没有快速地算法
- 其次符合最短路disv≤disu+wu,vdis_v\le dis_u+w_{u,v}disv≤disu+wu,v的形式
感觉最后求sns_nsn的最大值,应该是最长路,为什么图论上是跑最短路
首先约束和sns_nsn之间是逆向关系,并不是正比于
可以理解为最短路就是求出最严格的约束
sns_nsn的所有值都保证要满足所有的约束,自然要满足最严格的约束
e.g.
(i,j)=x1,(j,k)=x2,(i,k)=x3,x1+x2<x3(i,j)=x_1,(j,k)=x_2,(i,k)=x_3,x_1+x_2<x_3(i,j)=x1,(j,k)=x2,(i,k)=x3,x1+x2<x3既要满足disj≤disi+x1;disk≤disj+x2dis_j\le dis_i+x_1;dis_k\le dis_j+x_2disj≤disi+x1;disk≤disj+x2
又要满足disk≤disi+x3dis_k\le dis_i+x_3disk≤disi+x3
并且disk≤disj+x2≤disi+x1+x2≤disi+x3dis_k\le dis_j+x_2\le dis_i+x_1+x_2\le dis_i+x_3disk≤disj+x2≤disi+x1+x2≤disi+x3
根据不等式的原则,同小取小的最严格约束
这恰好匹配最短路的过程
所以差分约束的本质是转化为最短路问题
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 200005
#define Pair pair < int, int >
priority_queue < Pair, vector < Pair >, greater < Pair > > q;
int n, m;
int dis[maxn];
bool vis[maxn];
vector < Pair > G[maxn];void addedge( int u, int v, int w ) {G[u].push_back( make_pair( v, w ) );
}int main() {scanf( "%d %d", &n, &m );for( int i = 1, l, r, x;i <= m;i ++ ) {scanf( "%d %d %d", &l, &r, &x );addedge( l - 1, r, r - l + 1 - x );}for( int i = 0;i < n;i ++ ) {addedge( i, i + 1, 1 );addedge( i + 1, i, 0 );}memset( dis, 0x3f, sizeof( dis ) );dis[0] = 0; q.push( make_pair( 0, 0 ) );while( ! q.empty() ) {Pair now = q.top(); q.pop();int u = now.second;if( vis[u] or dis[u] ^ now.first ) continue;vis[u] = 1;for( auto nxt : G[u] ) {int v = nxt.first, w = nxt.second;if( dis[v] > dis[u] + w ) {dis[v] = dis[u] + w;q.push( make_pair( dis[v], v ) );}}}for( int i = 1;i <= n;i ++ )printf( "%d ", ( dis[i] - dis[i - 1] ) ^ 1 );return 0;
}