220707个人赛(题目来源Codeforces Round #674 (Div. 3) )
A
签到
#include<bits/stdc++.h>
using namespace std;
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;
}
void solve(){
int n = read() , p = read();
if( n <= 2 )
cout << "1\n";
else {
n -= 2;
cout << n / p + ( n % p > 0 ) + 1 << "\n";
}
return;
}
int32_t main() {
int t = read();
while( t -- )
solve();
return 0;
}
B
只要有一种是(1,2),(2,2)
相等的,就一定可以,反之不行
#include<bits/stdc++.h>
using namespace std;
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 n , m , flag;
void solve(){
n = read() , m = read() , flag = 0;
for( int i = 1 , a , b , c , d ; i <= n ; i ++ ){
cin >> a >> b >> c >> d;
if( b == c ) flag = 1;
}
if( m % 2 ) flag = 0;
cout << ( flag ? "YES\n" : "NO\n");
}
int32_t main() {
int t = read();
while( t -- )
solve();
return 0;
}
C
贪心题目,先自增到$\left \lfloor \sqrt n \right \rfloor $,然后一直分裂就好,证明可以用求导
#include<bits/stdc++.h>
#define int long long
using namespace std;
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 n , m , ans ;
vector< int > cnt , res;
void dfs( int mx , int t , int sum ){
if( t >= ans ) return;
if( sum >= n ) {
ans = t;
res = cnt;
return;
}
cnt.push_back(mx);
dfs( mx , t + 1 , sum + mx );
cnt.pop_back();
cnt.pop_back() , cnt.push_back(mx+1);
dfs( mx +1 , t + 1 , sum + 1 );
cnt.pop_back() , cnt.push_back(mx);
return;
}
void solve(){
n = read() , m = sqrt(n);
if( n == 1 ){
printf("0\n");
return;
}
cout << ( m - 1 ) + ( n / m + (n % m > 0 ) - 1 ) << "\n";
}
int32_t main() {
int t = read();
while( t -- )
solve();
return 0;
}
D
字段和为 0,说明在前缀和中他们的值相同,然后我们把所有前缀和相等的位置连一条边,问最少切多少次可以把所有的边切断,这样这道题就转化成了luogu P1803 凌乱的yyy / 线段覆盖
然后发现如果是1,2,3
这个三个点两年连边,发现1,3
连边是没有必要的,只要1,2
和2,3
的边断开他也一定会断开,所以连边规则就变成了相等且相邻的点之间连边
这样的话,我们就不用想P1803
那么做了,只要用 set 维护当前点的集合,如果当前点在集合中存在就要切一刀,同时集合中所有点先后的连边也都会被断开,所以可以直接把集合清空。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200000 + 5;
int n , cnt;
set< int > st;
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;
}
int32_t main() {
n = read();
st.insert(0);
for( int i = 1 , sum = 0 , x; i <= n ; i ++ )
{
x = read() , sum += x;
if( st.count(sum) )
cnt ++ , st.clear() , sum = x , st.insert(0);
st.insert(sum);
}
cout << cnt << endl;
return 0;
}
E
先说赢的最多的情况,如果B
出剪刀A
就要出石头直到一方的石头或剪刀用完,然后重复这个过程记录次数就好
在说赢得少的情况,如果B
出剪刀A
就要出布,直到一方完全出完,然后如果是B
的剪刀先出完,那么A
要继续在B
出布的时候出布,直到一方出完,如果此时还有剩余的布,就只能在B
出石头的时候出,这是剩下的布的数量才是必须赢且赢得最少的次数。
但是上述两种情况还要考虑剪刀石头布的顺序问题,因为数据很少直接枚举出所有的顺序就好
#include<bits/stdc++.h>
using namespace std;
int n , a[5] , b[5] , c[5] , d[5] , e[5] , ans = 1e9 + 7, res ,ans1 , res1;
int32_t main() {
cin >> n;
for( int i = 0 ; i < 3 ; i ++ ) cin >> a[i];
for( int i = 0 ; i < 3 ; i ++ ) cin >> b[i];
for( int i = 0 ; i < 3 ; i ++ )
c[i] = a[i] , d[i] = b[i] , e[i] = i;
do{
ans1 = res1 = 0;
for( int i = 0 ; i < 3 ; i ++ )
a[i] = c[i] , b[i] = d[i];
for( int i = 0 , x , y ; i < 3 ; i ++ )
x = e[i] , y = ( x + 1 ) % 3 , res1 += min( a[x] , b[y] );
for( int i = 0 , x , y ; i < 3 ; i ++ )
{
x = e[i] , y = ( x + 2 ) % 3 ;
if( a[x] >= b[y] ) a[x] -= b[y] , b[y] = 0;
else b[y] -= a[x] , a[x] = 0;
if( a[x] >= b[x] ) a[x] -= b[x] , b[x] = 0;
else b[x] -= a[x] , a[x] = 0;
}
for( int i = 0 ; i < 3 ; i ++ ) ans1 += a[i];
ans = min( ans , ans1 ) , res = max( res , res1 );
}while( next_permutation(e,e+3) );
cout << ans << " " << res << endl;
return 0;
}
F
没出现一个?
就会导致序列的数量乘3,这道题我的做法是dp,先说一下状态
f[i][0]
表示前i
位有多少个序列空序列
f[i][1]
表示前i
位有多少个a
f[i][2]
表示前i
位有多少个ab
f[i][3]
便是前i
位有多少个abc
显然答案是f[n][3]
然后考虑状态的转移
先说s[i] == a
, f[i][1]
就是之前a
的个数加上之前空序列个数
s[i] == b
,f[i][2]
就是之前的ab
的个数加上a
的个数 ,s[i]==c
时类似
但是a[i]==?
,情况比较复杂,每一种序列的倍数都会乘 3,加上比这种序列短一个的序列和这个?
组成的序列
然后推一下状态转移方程就好
然后发现数组可以滚动数组优化一下空间
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod =1e9+7;
string s;
int f[5];
int32_t main() {
f[0] = 1;
cin >> s >> s;
for( auto c : s ){
if( c == '?' ){
for( int i = 3 ; i >= 1; i -- )
f[i] = ( f[i] * 3 + f[i-1] ) % mod;
f[0] = f[0] * 3 % mod;
}
else {
int i = c - 'a' + 1 ;
f[i] = ( f[i] + f[i-1] ) % mod;
}
}
cout << f[3];
return 0;
}