Problem G Even Tree Split
题解:
对每条边,如果删去该边后两棵树点数都为奇数,则称其为好边。显见一个边集是合法的当且仅当边集内都为好边。则答案为2的c次方,其中c为好边数量。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
int n, ans, cnt[N];
vector<int> e[N];
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
void dfs(int u, int fa){
cnt[u] = 1;
for(auto v : e[u]){
if(v == fa) continue;
dfs(v, u);
cnt[u] += cnt[v];
}
if(u != 1 && cnt[u] % 2 == 0) ans++;
}
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++){
cnt[i] = 0;
e[i].clear();
}
ans = 0;
for(int i = 1, u, v; i < n; i++){
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0);
cout << qpow(2, ans) - 1 << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
}
Problem I Painting Game
题解:
打表找到规律即可。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int n, m, a[110], b[110];
string s;
void solve()
{
cin >> n >> s;
a[1] = 1;
a[1] = 1;
a[2] = 1;
a[3] = 1;
a[4] = 2;
a[5] = 2;
a[6] = 3;
a[0] = 0;
b[1] = 1;
b[2] = 1;
b[3] = 2;
b[4] = 2;
b[5] = 3;
b[6] = 3;
b[0] = 0;
if(s[0] == 'A') cout << n / 7 * 3 + a[n % 7] << '\n';
else cout << n / 7 * 3 + b[n % 7] << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
}
Problem C Wavy Trees
题解:
必定是一大一小交替,做两次取min即可。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 1e6 + 10;
int n, a[N], b[N];
string s;
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
int ans1 = 0, ans2 = 0;;
for(int i = 2; i <= n; i++){
b[i] = a[i] - a[i - 1];
}
for(int i = 2; i <= n; i++){
if(i % 2 == 0){
if(b[i] >= 0){
ans1 += b[i] + 1;
b[i + 1] += b[i] + 1;
}
}
else{
if(b[i] <= 0){
ans1 -= b[i] - 1;
b[i + 1] += b[i] - 1;
}
}
}
for(int i = 2; i <= n; i++){
b[i] = a[i] - a[i - 1];
}
for(int i = 2; i <= n; i++){
if(i % 2){
if(b[i] >= 0){
ans2 += b[i] + 1;
b[i + 1] += b[i] + 1;
}
}
else{
if(b[i] <= 0){
ans2 -= b[i] - 1;
b[i + 1] += b[i] - 1;
}
}
}
cout << min(ans1, ans2) << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
}
Problem A Winner Prediction
题解:
先让1号选手赢下所有和他有关的比赛,设此时选手i赢了ai场比赛。如果存在某个ai > a1则1号
选手不可能成为冠军。否则选手i至多还能再赢bi = a1 - ai场比赛。考虑建立一张网络流图:每场未
进行的比赛在图中用一个点表示,源点向它连容量为1的边,它向它的两个参赛选手的对应点各自连容量为1的边;选手i的对应点向汇点连容量为bi的边。计算该图最大流,若源点出发的边满流则答案为 YES ,否则为 NO 。
代码:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
using namespace std;
#define debug(x) cout<<#x<<": "<<(x)<<endl;
#define debug2(x,y) cout<<#x<<":"<<endl;for(int i=1;i<=y;++i)cout<<x[i]<<" ";cout<<endl;
#define mem(x,y) memset(x,y,sizeof(x));
#define int long long
#define double long double
const int inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
const double PI=acos(-1.0);
const int maxn=1e6+10;
struct Edge
{
int fr,to,cap,flow;
Edge(int f,int t,int c,int ff):fr(f),to(t),cap(c),flow(ff){}
};
int n,m1,m2;
int s,t;
vector<int> edg[maxn];
vector<Edge> net;
int dep[maxn];
int cur[maxn];
bool vis[maxn];
int cnt[maxn];
int dotnum[maxn];
void addedge(int fr,int to,int cap)
{
net.push_back(Edge(fr,to,cap,0));
net.push_back(Edge(to,fr,0,0));
int tot=net.size();
edg[fr].push_back(tot-2);
edg[to].push_back(tot-1);
}
bool bfs()
{
for(int i=0;i<=n;++i)
vis[i]=0;
queue<int> q;
q.push(s);
dep[s]=1;vis[s]=1;
while(!q.empty())
{
int p=q.front();
q.pop();
for(int i:edg[p])
{
if(vis[net[i].to]||net[i].flow>=net[i].cap)continue;
vis[net[i].to]=1;
q.push(net[i].to);
dep[net[i].to]=dep[p]+1;
}
}
return vis[t];
}
int dfs(int fr,int x)
{
if(fr==t||x==0)return x;
int res=0;
for(int &i=cur[fr];i<(int)edg[fr].size();++i)
{
Edge &it=net[edg[fr][i]];
if(dep[it.to]==dep[fr]+1)
{
int t=dfs(it.to,min(x,it.cap-it.flow));
it.flow+=t;
net[edg[fr][i]^1].flow-=t;
res+=t;
x-=t;
if(x<=0)break;
}
}
if(res==0)dep[fr]=0;
return res;
}
int dinic()
{
int res=0;
while(bfs())
{
for(int i=0;i<=n;++i)
cur[i]=0;
res+=dfs(s,inf);
}
return res;
}
void work()
{
int tot=0;s=++tot;t=++tot;
cin>>n>>m1>>m2;
net.clear();
for(int i=1;i<=n;++i)
cnt[i]=dotnum[i]=0;
for(int i=1;i<=n+m2+2;++i)
edg[i].clear();
int fr,to,flg;
for(int i=1;i<=m1;++i)
{
cin>>fr>>to>>flg;
if(flg==1)++cnt[fr];
else ++cnt[to];
}
int ans=0;
for(int i=1;i<=m2;++i)
{
cin>>fr>>to;
if(fr==1||to==1)++cnt[1];
else
{
if(dotnum[fr]==0)dotnum[fr]=++tot;
if(dotnum[to]==0)dotnum[to]=++tot;
addedge(s,++tot,1);
addedge(tot,dotnum[fr],1);
addedge(tot,dotnum[to],1);
++ans;
}
}
if(n==1)
{
cout<<"YES\n";
return;
}
for(int i=2;i<=n;++i)
{
if(cnt[i]>cnt[1])
{
cout<<"NO\n";
return;
}
if(dotnum[i])
addedge(dotnum[i],t,cnt[1]-cnt[i]);
}
n=tot;
if(dinic()==ans)cout<<"YES\n";
else cout<<"NO\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// cout<<fixed<<setprecision(6);
int _=1;
cin>>_;
while(_--)
work();
return 0;
}
Problem D Average Replacement
题解:
记deg(i)表示i的朋友数量,则每个连通块内为一定值。
代码:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
using namespace std;
#define debug(x) cout<<#x<<": "<<(x)<<endl;
#define debug2(x,y) cout<<#x<<":"<<endl;for(int i=1;i<=y;++i)cout<<x[i]<<" ";cout<<endl;
#define mem(x,y) memset(x,y,sizeof(x));
#define int long long
// #define double long double
const int inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
const double PI=acos(-1.0);
const int maxn=1e6+10;
int n,m;
int a[maxn];
vector<int> edg[maxn];
int d[maxn];
double ans[maxn];
int fa[maxn],num[maxn],sum[maxn];
void init()
{
for(int i=1;i<=n;++i)
{
fa[i]=i;
num[i]=1;
sum[i]=0;
}
}
int find(int x)
{
if(fa[x]!=x)return fa[x]=find(fa[x]);
return fa[x];
}
void merge(int x,int y)
{
x=find(x);y=find(y);
if(x==y)return;
if(num[x]<num[y])swap(x,y);
fa[y]=x;
num[x]+=num[y];
sum[x]+=sum[y];
}
void work()
{
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;++i)
{
edg[i].clear();
d[i]=0;
}
init();
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
int fr,to;
for(int i=1;i<=m;++i)
{
scanf("%lld %lld",&fr,&to);
edg[fr].push_back(to);
edg[to].push_back(fr);
++d[fr];++d[to];
}
for(int i=1;i<=n;++i)
sum[i]=d[i]+1;
for(int fr=1;fr<=n;++fr)
{
for(int to:edg[fr])
{
merge(fr,to);
}
}
for(int i=1;i<=n;++i)
ans[i]=0;
for(int i=1;i<=n;++i)
{
int fa=find(i);
ans[fa]+=1.0*(d[i]+1)*a[i];
}
for(int i=1;i<=n;++i)
{
int fa=find(i);
if(fa!=i)continue;
ans[i]=ans[i]/sum[i];
}
for(int i=1;i<=n;++i)
{
int fa=find(i);
// cout<<ans[fa]<<'\n';
printf("%.6lf\n",ans[fa]);
}
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
// cout<<fixed<<setprecision(6);
int _=1;
scanf("%lld",&_);
while(_--)
work();
return 0;
}
Problem B Photos
代码:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector<pair<int,int> > S,T;vector<int> V;
int sumlen[200000];
int query_pos(int x)
{
int pos=lower_bound(T.begin(),T.end(),make_pair(x+1,-1))-T.begin();
if(pos==0)return x;
if(T[pos-1].second>=x)return -1;
return x-sumlen[pos-1];
}
const long long MOD=998244353;
int add(int x,int y){return x+y>=MOD?x+y-MOD:x+y;}
int sub(int x,int y){return x>=y?x-y:x+MOD-y;}
struct mat
{
long long num[2][2];
long long *operator[](int x){return num[x];}
mat(){for(int i=0;i<2;i++)for(int j=0;j<2;j++)num[i][j]=0;}
};
mat operator*(mat A,mat B)
{
mat C;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)C[i][j]=add(C[i][j],A[i][k]*B[k][j]%MOD);
}
}
return C;
}
mat fast_pow(mat A,int p)
{
mat D;D[0][0]=D[1][1]=1;
while(p)
{
if(p&1)D=D*A;A=A*A;p>>=1;
}
return D;
}
int main()
{
//freopen("1002.in","r",stdin);
//freopen("1002.out","w",stdout);
int TT=0;scanf("%d",&TT);
mat A,B;
A[0][0]=1,A[1][0]=1,A[0][1]=1,A[1][1]=2;
B[0][0]=0,B[1][0]=1,B[0][1]=0,B[1][1]=2;
while(TT--)
{
int n=0,m=0;scanf("%d%d",&n,&m);
for(int i=1,x=0,y=0;i<=m;i++)
{
scanf("%d%d",&x,&y);if(x>y)swap(x,y);
//if(x==1)puts("??");
if(x<y){S.push_back(make_pair(x,y-1));}
V.push_back(y);
}
sort(S.begin(),S.end());
for(int i=0;i<S.size();i++)
{
if(T.empty()||T.back().second+1<S[i].first)T.push_back(S[i]);
else T.back().second=max(T.back().second,S[i].second);
}
for(int i=0;i<T.size();i++)
{
sumlen[i]=T[i].second-T[i].first+1;if(i)sumlen[i]+=sumlen[i-1];
}
sort(V.begin(),V.end());V.erase(unique(V.begin(),V.end()),V.end());
int lst=0;mat ans;ans[0][0]=ans[1][1]=1;
for(int i=0;i<V.size();i++)
{
int cur=query_pos(V[i]);if(cur==-1)continue;
ans=ans*fast_pow(A,cur-lst-1);
ans=ans*B;
lst=cur;
}
ans=ans*fast_pow(A,query_pos(n)-lst);
printf("%lld\n",add(ans[0][0],ans[1][0]));
S.clear(),T.clear(),V.clear();
}
}