CF1598
Computer Game
深搜,启动!
#include<bits/stdc++.h>
using namespace std;
#define inl inline
#define eb emplace_back
#define pb pop_back
#define endl '\n'
#define mid (l+r>>1)
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define getchar() cin.get()
const int dx[9] = { 0 , 1 , 0 , -1 , 1 , 1 , -1 , -1 };
const int dy[9] = { 1 , 0 , -1 , 0 , 1 , -1 , 1 , -1 };
const int N = 1e2 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , flag , vis[3][N];
char mp[3][N];
inl int check ( int x , int y ) { return 1 <= x && x <= 2 && 1 <= y && y <= n && mp[x][y] == '0'; }
void dfs ( int x , int y )
{
if ( x == 2 && y == n ) return flag = 1 , void();
for ( int i = 0 ; i < 8 ; i ++ )
{
int tx = x + dx[i] , ty = y + dy[i];
if ( vis[tx][ty] || !check(tx,ty) ) continue;
vis[tx][ty] = 1 , dfs ( tx , ty );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
flag = 0;
memset ( vis , 0 , sizeof vis );
n = read();
for ( int i = 1 ; i <= 2 ; i ++ ) for ( int j = 1 ; j <= n ; j ++ ) cin >> mp[i][j];
vis[1][1] = 1;
dfs ( 1 , 1 );
cout << ( flag ? "YES" : "NO" ) << endl;
}
return 0;
}
Groups
考虑枚举两个不同的时间点进行比对。
记录 \(cnt1\) 为第一种课的人数,\(cnt2\) 为第二种课的人数,\(cnt\) 为两个课的交集。
那么合法条件为 \(cnt1\ge \frac n 2 \and cnt2\ge \frac n2\and cnt1+cnt2-cnt\ge n\)。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define getchar() cin.get()
const int N = 1e3 + 5;
const int mod = 1e9 + 7;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N][6];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
for ( int i = 1 ; i <= n ; i ++ ) for ( int j = 1 ; j <= 5 ; j ++ ) a[i][j] = read();
for ( int j = 1 ; j <= 5 ; j ++ )
for ( int k = j + 1 ; k <= 5 ; k ++ )
{
int cnt1 = 0 , cnt2 = 0 , cnt = 0;
for ( int i = 1 ; i <= n ; i ++ )
{
cnt1 += a[i][j];
cnt2 += a[i][k];
cnt += ( a[i][j] && a[i][k] );
}
if ( cnt1 >= n / 2 && cnt2 >= n / 2 && cnt1 + cnt2 - cnt >= n ) { cout << "YES" << endl; goto flg; }
}
cout << "NO" << endl;
flg:;
}
}
Delete Two Elements
推一下柿子:(设我们现在到的点为 \(i\))
我们要求的就是满足这样的柿子的方案数:\(\frac {sum} n=\frac {sum-a_i-a_x} {n-2},x<i\)。
则 \(a_x=\frac{2\times sum} n-a_i\)。
因为数列中都是整数,那么当 \(\frac {2\times sum} n\) 不为整数的时候显然无解。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define getchar() cin.get()
#define int long long
const int N = 2e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , ans , k , a[N];
map<int,int> mp;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
ans = 0 , k = 0 , mp.clear();
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , k += a[i];
k *= 2;
if ( k % n ) { cout << 0 << endl; continue; }
k /= n;
for ( int i = 1 ; i <= n ; i ++ ) ans += mp[k-a[i]] , mp[a[i]] ++;
cout << ans << endl;
}
}
Training Session
计数题。
首先考虑正向计数,发现答案为满足 \(a\) 三个不相同和满足 \(b\) 三个不相同的方案数的加和,还要减去同时满足 \(a\) 三个不相同和 \(b\) 三个不相同的方案数量,比较麻烦。
正难则反,我们用总数减掉不合法的情况。
显然总操作次数为 \(C_n^3=\frac {n\times(n-1)\times(n-2)}6\)。
因为没有两个相等的点对,那么不合法的情况一定是当前这个点对和一个相同的 \(a\) 和一个相同的 \(b\) 组成。
因为如果是三个相同的 \(a\),那么三个 \(b\) 一定是互不相同的,三个相同的 \(b\) 同理。
那么乘法计数一下即可。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define getchar() cin.get()
#define int long long
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N] , b[N] , ans;
map<int,int> mpa , mpb;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read() , ans = n * ( n - 1 ) * ( n - 2 ) / 6;
mpa.clear() , mpb.clear();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , b[i] = read() , mpa[a[i]] ++ , mpb[b[i]] ++;
for ( int i = 1 ; i <= n ; i ++ ) ans -= ( mpa[a[i]] - 1 ) * ( mpb[b[i]] - 1 );
cout << ans << endl;
}
}
Staircases
我们设 \(f_{i,j,0/1}\) 表示到 \((i,j)\) 点,当前格子作为右上/左下拐点的方案数。
初始化 \(f_{i,j,0}=f_{i,j,1}=1\)。
那么我们首先将全部为 \(0\) 的情况的答案先算出来,即:\(f_{i,j,0}\leftarrow f_{i-1,j,1},f_{i,j,1}\leftarrow f_{i,j-1,0}\)。
\(ans=\sum_{i=1}^n\sum_{j=1}^m f_{i,j,0}+f_{i,j,1}-1\)。
考虑一个修改 \((x,y)\) 的贡献,所有经过这个点的合法楼梯,那么我们向四个方向搜索并组合,累计修改即可。
注意当 \((x,y)\) 点不合法的时候,我们是不能直接 \(break\) 的。
参考了这篇代码的书写方式,使修改操作更加简洁。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define getchar() cin.get()
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
const int N = 1000 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , q , ans , f[N][N][2] , a[N][N] , cnt[4];//(i,j),作为右上或左下拐点。
vector<pii> d[4] = { vector<pii> { {0,1},{1,0} } , vector<pii> { {1,0},{0,1} } , vector<pii> { {0,-1},{-1,0} } , vector<pii> { {-1,0},{0,-1} } };
int check ( int x , int y ) { return 1 <= x && x <= n && 1 <= y && y <= m ; }
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , q = read();
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= m ; j ++ )
f[i][j][0] = f[i][j][1] = 1 , f[i][j][0] += f[i-1][j][1] , f[i][j][1] += f[i][j-1][0] , ans += f[i][j][0] + f[i][j][1] - 1;
for ( int i = 1 ; i <= q ; i ++ )
{
int x = read() , y = read();
fill ( cnt , cnt + 4 , 0 );
for ( int i = 0 ; i < 4 ; i ++ )
{
int op = 0 , tx = x , ty = y;
while ( check(tx,ty) && ( !a[tx][ty] || tx == x && ty == y ) ) ++ cnt[i] , tx += d[i][op].fi , ty += d[i][op].se , op ^= 1;
}
ans += ( a[x][y] == 1 ? 1 : -1 ) * ( cnt[0] * cnt[3] + cnt[1] * cnt[2] - 1 );
a[x][y] ^= 1;
cout << ans << endl;
}
return 0;
}