AcWing题目选做
1934. 贝茜放慢脚步
一个二路归并,首先要把所有的点分别排序,每次计算当前的是想到下一个时间点还是下一个位置点,选取先到的就好了
#include<bits/stdc++.h>
using namespace std;
int n;
vector<double> a , b;
int main()
{
cin >> n;
char op;
for( double x ; n ; n -- )
{
cin >> op >> x;
if( op == 'T' ) a.push_back(x);
else b.push_back(x);
}
b.push_back(1000);
sort( a.begin() , a.end() ) , sort( b.begin() , b.end() );
int i = 0 , j = 0;
double s = 0 , t = 0 , v = 1;
while( i < a.size() || j < b.size() )
if( i < a.size() && ( a[i] - t ) < ( b[j] - s ) * v )
{
s += ( a[i] - t ) / v;
t = a[i];
i ++ , v ++;
}
else
{
t += ( b[j] - s ) * v;
s = b[j];
j ++ , v ++;
}
printf("%.0lf\n" , t );
}
1738. 蹄球
首先可以的知道每个点最多只能指向一个点,但是可能被之多两个点指向,也就是说点的出度为一入度小于等于二,也就是一个基环树,同时环最大只能是二,我们要找到所有的根也就是入度为零的点,然后可能存在一些单独环,每个环也算一个
#include<bits/stdc++.h>
using namespace std;
const int N = 105 , inf = 1e8;
int n , a[N] , p[N] , d[N] , res;
int main()
{
cin >> n;
for( int i = 1 ; i <= n ; i ++ ) cin >> a[i];
a[0] = - inf , a[n+1] = inf;
sort( a + 1 , a + 1 + n );
for( int i = 1 ; i <= n ; i ++ )
if( ( a[i] - a[i-1] ) <= ( a[i+1] - a[i] ) )
p[i] = i - 1 , d[i-1] ++;
else p[i] = i + 1 , d[i+1] ++;
for( int i = 1 ; i <= n ; i ++ )
if( d[i] == 0 ) res += 2;
else if ( p[p[i]] == i && d[i] == 1 && d[p[i]] == 1 ) res += 1;
cout << res / 2 << endl;
return 0;
}
1789. 牛为什么过马路 II
统计每个牛的区间,然后枚举所有牛的组合,判断时候有交集
#include<bits/stdc++.h>
using namespace std;
string s;
int a[26][2] , cnt;
int main()
{
cin >> s;
for( int i = 1 , t ; i <= 52 ; i ++ )
{
t = s[i-1]-'A';
if( a[t][0] ) a[t][1] = i;
else a[t][0] = i;
}
for( int i = 0 ; i < 26 ; i ++ )
for( int j = 0 ; j < 26 ; j ++ )
if( i == j ) continue;
else if( a[i][0] < a[j][0] && a[j][0] < a[i][1] && a[i][1] < a[j][1] ) cnt ++;
cout << cnt << endl;
return 0;
}
1776. 牛的基因组学
枚举判断,每一位上斑点牛和非斑点牛是否有相同的碱基
package TestDemo;
import java.util.Scanner;
public class code01 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt() , m = in.nextInt();
String [] a = new String[n];
String [] b = new String[n];
for( int i = 0 ; i < n ; i ++ ){
a[i] = in.next();
}
for( int i = 0 ; i < n ; i ++){
b[i] = in.next();
}
int res = 0;
for( int c = 0 , flag = 1 ; c < m ; flag = 1 , c ++ ){
int [] cnt = new int[26];
for( int r = 0 ; r < n ; r ++ ){
cnt[ a[r].charAt(c) - 'A' ] = 1;
}
for( int r = 0 ; r < n ; r ++ ){
if (cnt[ b[r].charAt(c) - 'A' ] == 1){
flag = 0;
break;
}
}
res += flag;
}
System.out.println(res);
}
}
1762. 牛的洗牌
这题就是考读题的吧,读题读错了,就是每次做交换就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int n , a[N] , val[N] , cur[N];
int main()
{
cin >> n;
for( int i = 1 ; i <= n ; i ++ )
cin >> a[i];
for( int i = 1 ; i <= n ; i ++ )
cin >> val[i];
for( int t = 1 ; t <= 3 ; t ++ )
{
for( int i = 1 ; i <= n ; i ++ )
cur[i] = val[ a[i] ];
for( int i = 1 ; i <= n ; i ++ )
val[i] = cur[i];
}
for( int i = 1 ; i <= n ; i ++ )
cout << val[i] << '\n';
return 0;
}
1750. 救生员
这道题就是用差分来维护,因为数据范围很小直接暴力做就好了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 105 , M = 1005;
int n , m , l[N] , r[N] , b[M] , res , sum , ans ;
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x ;
}
int main()
{
n = read();
for( int i = 1 ; i <= n ; i ++ )
l[i] = read() , r[i] = read() , m = max( r[i] , m ) , b[ l[i] ] ++ , b[ r[i] ] -- ;
for( int i = 1 ; i <= n ; i ++ )
{
b[ l[i] ] -- , b[ r[i]] ++ ;
sum = ans = 0;
for( int j = 0 ; j < m ; j ++ )
sum += b[j] , ans += ( sum > 0 );
res = max( res , ans );
b[ l[i] ] ++ , b[ r[i] ] --;
}
cout << res << endl;
}
1715. 桶列表
这里的桶的标号是无效信息,我们只要统计出每一时刻的说需要桶的数量并取最大值就行了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 105 , M = 1005;
int n , m , b[M] , res ;
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x ;
}
int main()
{
n = read();
for( int i = 1 , l , r , v ; i <= n ; i ++ )
l = read() , r = read() , v = read() , b[l] += v , b[r+1] -= v , m = max( m , r );
for( int i = 1 ; i <= m ; i ++ )
b[i] += b[i-1] , res = max( res , b[i] );
cout << res << endl;
return 0;
}
1443. 拍照
因为有a[i] = b[i-1] - a[i-1]
,所以只要枚举出a[1]
就可以递推出完整的序列
然后要保证a[i]
在[1,n]
中且不能重复即可
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+5;
int n , a[N] , b[N];
bitset<N> vis;
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x ;
}
int main()
{
n = read();
for( int i = 1 ; i < n ; i ++ )
b[i] = read();
for( a[1] = 1 ; ; a[1]++ )
{
vis.reset() , vis[ a[1] ] = 1;
int f = 1;
for( int i = 2 ; i <= n && f ; i ++ )
{
a[i] = b[i-1] - a[i-1];
if( a[i] < 1 || a[i] > n ) f = 0;
else if ( vis[ a[i] ] ) f = 0;
else vis[ a[i] ] = 1;
}
if( !f ) continue;
for( int i = 1 ; i <= n ; i ++ )
cout << a[i] << ' ';
cout << endl;
return 0;
}
return 0;
}
1672. 疯狂的科学家
因为一定有最有解满足所有的集合都不想交,所以用双指针扫一遍就好
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005;
int n , cnt;
string a,b;
int main()
{
cin >> n >> a >> b;
for( int i = 0 , j ; i < n ; i ++ )
{
if( a[i] != b[i] )
{
j = i + 1;
while( j < n && a[j] != b[j] ) j ++;
cnt ++ , i = j;
}
}
cout << cnt << endl;
return 0;
}
1660. 社交距离 II
如果要保证源头最少就要保证他的传染范围最大,所以先排序,然后通过便利查找相邻的感染与未感染间距的最小值,这个值减一就是传染的最大距离,我们可以通过双指针扫出有多少个感染源
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005;
int n , MaxRange = 1e7 + 5 , res;
pair< int , int > p[N];
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
int main()
{
n = read();
for( int i = 1 ; i <= n ; i ++ )
p[i].first = read() , p[i].second = read();
sort( p + 1 , p + 1 + n );
for( int i = 2 ; i <= n ; i ++ )
{
if( p[i].second == p[i-1].second ) continue;
MaxRange = min( MaxRange , p[i].first - p[i-1].first - 1 );
}
for( int i = 1 , j ; i <= n ; i ++ )
if( p[i].second == 1 ){
res ++;
j = i + 1;
while( j <= n && p[j-1].first + MaxRange >= p[j].first ) j ++;
i = j - 1;
}
cout << res << endl;
return 0;
}
1471. 牛奶工厂
这道题可以用Floyd
来维护一下,然后把所有的点便利一遍
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 105;
int n , cnt;
int vis[N][N];
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
int main()
{
n = read();
for( int i = 1 , u , v ; i < n ; i ++ )
u = read() , v = read() , vis[u][v] = 1;
for( int i = 1 ; i <= n ; i ++ )
vis[i][i] = 1;
for( int k = 1 ; k <= n ; k ++ )
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= n ; j ++ )
{
if( vis[i][j] ) continue;
if( vis[i][k] && vis[k][j] )
vis[i][j] = 1;
}
for( int i = 1 ; i <= n ; i ++ )
{
cnt = 0;
for( int j = 1 ; j <= n ; j ++ )
cnt += vis[j][i];
if( cnt == n )
printf("%d\n", i ) , exit(0);
}
printf("-1\n");
return 0;
}
1929. 镜子田地
通过分析可知每个边界点只有一条边,非边界点有两条边,这样可以知道图的每一个联通块一定是一个环或链,因为边界点都在链上,所以从每一个边界点便利一遍找出最长链即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1005;
const int dx[4] = {-1 , 0 , 1 , 0 } , dy[4] = { 0 , 1 , 0 , -1 };
int n , m ;
char g[N][N];
int dfs( int x , int y , int d )// d 是方向
{
if( x < 0 || y < 0 || x >= n || y >= m ) return 0;
if( g[x][y] == '/' ) d ^= 1;
else d ^= 3;
return dfs( x + dx[d] , y + dy[d] , d ) + 1;
}
int main()
{
cin >> n >> m;
for( int i = 0 ; i < n ; i ++ )
cin >> g[i];
int res = 0;
for( int i = 0 ; i < n ; i ++ )
res = max( res , dfs(i,0,1) ) , res = max( res , dfs( i , m-1 , 3) );
for( int i = 0 ; i < m ; i ++ )
res = max( res , dfs( n , i , 2 ) ) , res = max( res , dfs( n-1 , i , 0 ) );
cout << res << endl;
}
1460. 我在哪?
题目让我找一最短多长的字符串所有子串不重复,可以用二分来枚举子串的长度,然后把所有的子串放在set
中判重即可,但是由于字符串截取很慢可以中字符串的hash来解决一下
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 105 , mod = 1e9+7;
int res , n ;
ll h[N] , p[N];
string s;
ll Hash( int l , int r ){
return ( h[r] - h[l-1] * p[r-l+1] % mod + mod ) % mod;
}
bool check( int len ){
set<int> st;
for( int i = 1 , key ; i <= n - len + 1 ; i ++ )
{
key = Hash( i , i+len-1 );
if( st.count( key) ) return 0;
st.insert(key);
}
return 1;
}
int main()
{
cin >> n >> s;
p[0] = 1;
for( int i = 1 ; i <= n ; i ++ )
h[i] = ( h[i-1]*26 + s[i-1] - 'A' ) % mod , p[i] = ( p[i-1] * 26 ) % mod;
int l = 1 , r = n , mid;
while( l <= r )
{
mid = ( l + r ) >> 1;
if( check(mid) ) res = mid , r = mid - 1;
else l = mid + 1;
}
cout << res << endl;
}
1696. 困牛排序
每一个点至多用一次操作就可以放在正确的位置上,若操作一个点,必须把前面所的点都操作一次,所以要找到最后一个逆序的
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int n , a[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++ )
cin >> a[i];
for( int i = n-1 ; i >= 1 ; i -- )
if( a[i] > a[i+1] )
{
cout << i << endl;
return 0;
}
cout << "0\n";
return 0;
}