比赛链接:https://codeforces.com/contest/1709
题解:
AB
水题
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f;
void solve(){
int x;scanf("%d",&x);
int a[5];
for(int i=1;i<=3;i++)scanf("%d",&a[i]);
int cnt=1;
while(1){
if(a[x]){
++ cnt;
int tmp = a[x];
a[x] = 0;
x = tmp;
}else break;
}
if(cnt == 3)puts("YES");
else puts("NO");
}
signed main(){
int te;scanf("%d",&te);
while(te--)solve();
return 0;
}
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f,maxn=2e5+5;
int n,m,a[maxn];
LL sum[maxn],sum2[maxn];
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=2;i<=n;i++){
sum[i] = sum[i-1];
if(a[i] < a[i-1])sum[i] += a[i-1] - a[i];
}
for(int i=n-1;i>=1;i--){
sum2[i] = sum2[i+1];
if(a[i] < a[i+1])sum2[i] += a[i+1]-a[i];
}
while(m--){
int x,y;scanf("%d%d",&x,&y);
if(x<y)printf("%I64d\n",sum[y]-sum[x]);
else printf("%I64d\n",sum2[y]-sum2[x]);
}
return 0;
}
C
题目保证一定存在解,观察可知开始的?全填( 一定是一个解
然后考虑是否存在第二个解,显然把最后一个'('换成')'再判断是否有解即可(因为如果还有其它解的话,这个解一定被包含在内)
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;
char s[maxn];
void solve(){
scanf("%s", s+1);
int n=strlen(s+1);
int a1=0,a2=0;
for(int i=1;i<=n;i++)
if(s[i] == '(')++ a1;
else if(s[i] == ')')++ a2;
a1 = n/2 - a1, a2 = n/2 - a2;
if(a1 == 0 || a2 == 0){
puts("YES");
return ;
}
int fg = 1;
for(int i=1;i<=n;i++){
if(s[i] == '?'){
if(a1 == 1 && fg){
if(a2)s[i] = ')', -- a2, fg = 0;
else s[i] = '(', -- a1;
}else{
if(a1)s[i] = '(', -- a1;
else s[i] = ')', -- a2;
}
}
}
int tmp = 0;
for(int i=1;i<=n;i++)
if(s[i] == '(')++ tmp;
else{
-- tmp;
if(tmp < 0){
puts("YES");
return ;
}
}
puts("NO");
}
signed main(){
int te;scanf("%d",&te);
while(te--)solve();
return 0;
}
D
显然xy独立,先判一下y之间距离是否为k的倍数
接着看能否“上去”,利用st表维护一下区间max,看起点往上走k的倍数步且超过max之后是否会出边界
我把st表写错了。。(int)log(1.0 * (r-l+1)) / log(2.0)
是错误的!!!
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#include <cmath>
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e6+5;
int n,m;
int a[maxn], st[maxn][22];
int query(int l,int r){
int j = (int)(log(1.0 * (r-l+1)) / log(2.0));
return max(st[l][j], st[r-(1<<j)+1][j]);
}
signed main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),st[i][0] = a[i];
for(int j=1;j<=19;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j] = max(st[i][j-1], st[i+(1<<(j-1))][j-1]);
int qe;scanf("%d",&qe);while(qe--){
int x1,y1,x2,y2,k;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
if(y1 > y2)swap(y1, y2), swap(x1, x2);
if(x1 == x2 && y1 == y2){
puts("YES");
continue;
}
int dcol = y2 - y1;
if(dcol % k != 0 || abs(x1-x2) %k != 0){
puts("NO");
continue;
}
int mx = query(y1, y2);
int tp = (m - x1) / k * k + x1;
if(tp > mx)puts("YES");
else puts("NO");
}
return 0;
}
E
首先一条路径 \((u,v)\) 的异或和可以化为 \(d[u] \ xor\ d[v] \ xor\ a[lca]\) ,其中 \(d[u]\) 是 \(u\) 到 1 路径的异或和
考虑对一个点,维护其子树内有多少种 \(d\) ,这显然可以用 set 维护
然后往当前点 \(x\) 添加子树 \(u\) 的时候,可以使用启发式合并。如果遇到 \(u\) 的子树中有 \(d[v]\) ,而且 \(d[v] \ xor\ a[x]\) 出现在 \(x\) 的set中,那么说明 \(x\) 的子树中存在某一点 \(w\) ,\(w \rightarrow v\) 的权值异或和是 0,因此需要修改 \(x\) 的权值(显然这是最优的方案),因为可以任意修改,所以可以保证对于 \(x\) 的子树中只修改1次就可以了,也就是说在添加完 \(x\) 的所有子树后把 \(x\) 的set清空
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <set>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;
int n, a[maxn];
vector<int>g[maxn];
set<int>S[maxn];
int xo[maxn];
void dfs0(int x,int fat=0){
xo[x] ^= a[x];
for(int u : g[x])if(u!=fat){
xo[u] ^= xo[x];
dfs0(u, x);
}
}
int ans = 0;
void dfs(int x,int fat=0){
int gg = 0;
S[x].insert(xo[x]);
for(int u : g[x])if(u!=fat){
dfs(u, x);
if(S[u].size() > S[x].size())swap(S[x], S[u]);
// combine u to x
for(int i : S[u])if(S[x].count(i ^ a[x])){gg = 1;break;}
for(int i : S[u])S[x].insert(i);
}
// printf("%d %d\n",x,gg);
// for(int i : S[x])printf("%d ",i);debug();
if(gg){
++ ans;
S[x].clear();
}
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++){
int x,y;scanf("%d%d",&x,&y);
g[x].push_back(y), g[y].push_back(x);
}
dfs0(1);
dfs(1);
printf("%d\n",ans);
return 0;
}
F
注意到出现了前缀,而且字符串又挺多,考虑 01 trie
发现对于某个01串的 \(c_s\) 限制,可以转化为该01串在trie上的点,比如 \(x\),则 \(fa[x] \rightarrow x\) 的容量即为 \(c_s\),题目要求的就是从源点开始跑最大流,所有叶子为汇点,最大流为 \(f\) 的方案数,我们只需要给边赋容量即可
考虑树形dp,因为同层的点都是等价的,所以只需要考虑 \(n\) 个结点即可
设 \(dp[x][i]\) 表示考虑到第 \(x\) 结点,\(x\) 及 \(x\) 子树这块连通块能流过的流量为 \(i\) 的赋值方案数
则有$$dp[x][i] = \sum_{j,k}$$$$ (dp[s1][j] \times dp[s2][k], 如果 j+k>i) $$$$ (dp[s1][j] \times dp[s2][k] * (k-i+1),如果 j+k=i)$$
\(s1, s2\) 为 \(x\) 的两个儿子
理解一下就是第一种情况,必须要限制 \(fa[x] \rightarrow x\) 这条边的容量为 \(i\) 才能满足状态,因此只有一种情况,第二种情况只要 \(fa[x] \rightarrow x\) 大于等于 \(i\) 即可,有 \((k-i+1)\) 种情况
又发现实际上 \(dp[s1]\) 和 \(dp[s2]\) 也是等价的,因此相当于自己和自己卷积就是一个转移
第一种情况,卷积完求个后缀和。第二种情况也同理
代码中的\(F[j] G[j]\)实际上就是当前 i 的 \(dp[i][j]\)
注意一下最后还需要转移一下,\(F=F*F\) 之后求 \(F[f]\) 就是流量恰好为 \(f\) 的情况
时间复杂度 \(O(nk \log k)\)
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, mod =998244353;
int pw(int a, int b)
{
int res = 1;
while(b) {
if(b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
namespace Poly
{
const int N = 2000007;
#define mul(x, y) (1ll * x * y >= mod ? 1ll * x * y % mod : 1ll * x * y)
#define minus(x, y) (1ll * x - y < 0 ? 1ll * x - y + mod : 1ll * x - y)
#define plus(x, y) (1ll * x + y >= mod ? 1ll * x + y - mod : 1ll * x + y)
#define ck(x) (x >= mod ? x - mod : x)//取模运算太慢了
typedef vector<int> poly;
const int G = 3;//根据具体的模数而定,原根可不一定不一样!!!
//一般模数的原根为 2 3 5 7 10 6
const int inv_G = pw(G, mod - 2);
int RR[N], deer[2][21][N], inv[N];
void init(const int t) {//预处理出来NTT里需要的w和wn,砍掉了一个log的时间
for(int p = 1; p <= t; ++ p) {
int buf1 = pw(G, (mod - 1) / (1 << p));
int buf0 = pw(inv_G, (mod - 1) / (1 << p));
deer[0][p][0] = deer[1][p][0] = 1;
for(int i = 1; i < (1 << p); ++ i) {
deer[0][p][i] = 1ll * deer[0][p][i - 1] * buf0 % mod;//逆
deer[1][p][i] = 1ll * deer[1][p][i - 1] * buf1 % mod;
}
}
inv[1] = 1;
for(int i = 2; i <= (1 << t); ++ i)
inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod;
}
int NTT_init(int n) {//快速数论变换预处理
int limit = 1, L = 0;
while(limit <= n) limit <<= 1, L ++ ;
for(int i = 0; i < limit; ++ i)
RR[i] = (RR[i >> 1] >> 1) | ((i & 1) << (L - 1));
return limit;
}
void NTT(poly &A, int type, int limit) {//快速数论变换
A.resize(limit);
for(int i = 0; i < limit; ++ i)
if(i < RR[i])
swap(A[i], A[RR[i]]);
for(int mid = 2, j = 1; mid <= limit; mid <<= 1, ++ j) {
int len = mid >> 1;
for(int pos = 0; pos < limit; pos += mid) {
int *wn = deer[type][j];
for(int i = pos; i < pos + len; ++ i, ++ wn) {
int tmp = 1ll * (*wn) * A[i + len] % mod;
A[i + len] = ck(A[i] - tmp + mod);
A[i] = ck(A[i] + tmp);
}
}
}
if(type == 0) {
for(int i = 0; i < limit; ++ i)
A[i] = 1ll * A[i] * inv[limit] % mod;
}
}
poly poly_mul(poly A, poly B) {//多项式乘法
int deg = A.size() + B.size() - 1;
int limit = NTT_init(deg);
poly C(limit);
NTT(A, 1, limit);
NTT(B, 1, limit);
for(int i = 0; i < limit; ++ i)
C[i] = 1ll * A[i] * B[i] % mod;
NTT(C, 0, limit);
C.resize(deg);
return C;
}
}
//using namespace Poly;
int n,k,f;
signed main(){
scanf("%d%d%d",&n,&k,&f);
if(f > 2*k)return puts("0"), 0;
vector<int>F(k+1, 1);
Poly::init(20);
for(int i=1;i<=n-1;i++){
vector<int>G = Poly::poly_mul(F,F), tmp = G;
for(int j = G.size() - 2;j >= 0; j--)(G[j] += G[j+1]) %= mod; // 后缀和 第一种情况
for(int j=0;j<G.size();j++){
if(j > k)G[j] = 0; // 流量最大就是 k 了,超过 k 就没有意义了
else (G[j] += 1ll * tmp[j] * (k-j) % mod)%= mod; // tmp[j]*(k-j) 就是第二种情况,注意G[]已经改了所以用tmp
}
F = G;
F.resize(k + 1);
}
F = Poly::poly_mul(F, F);
printf("%d\n",F[f]);
return 0;
}
标签:int,题解,1ll,CF1709,maxn,mod,include,define
From: https://www.cnblogs.com/SkyRainWind/p/16949572.html