对不起,丢人了Orz
A - Odd Selection
一开始奇数看错偶数,看错之后就开始慌了,疯狂WA之后心态就崩了Orz。
其实这道题这个数据范围已经降低要求了,只有1e3,算是给了一定的提示了。
首先,统计奇偶是基操。
很明显,这道题需要分类讨论:
若没有奇数,肯定不行,所以直接输出No
否则,我们枚举选择偶数的数量(因为一个数加上偶数之后,奇偶性不变,可以少考虑一些,也可以起到"充数"的效果)i(从多到少枚举),若(x-i)为奇数,可以直接break,剩下的x-i个数让奇数去填满。若奇数不够填,则No,否则Yes。
被惯性思维所困,只想到根据ji和ou去判断,但没想到这种操作需要注意很多细节Orz。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//鐪嬫槸鍚﹁mod
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
int t,n,x;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
clock_t c1 = clock();
//===========================================================
read(t);
while(t--){
int ji=0,ou=0;
read(n),read(x);
rep(i,1,n){
int e;
read(e);
if(e%2) ji++;
else ou++;
}
if(ji==0){
puts("No");
}
else{
per(i,0,ou){
if((x-i)%2){
x-=i;
break;
}
}
if(x%2&&x<=ji){
puts("Yes");
}
else{
puts("No");
}
}
}
//===========================================================
std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
B - Subsequence Hate
害。。太菜了。。都比赛快结束才想出来。。。
题目中说"010"或"101"都不行,也就是说,符合条件的,其实只有类似000111111或者11110000这种0和1分别集中在两边的,那么,我们可以先前缀和处理下这个字符串,统计到每个位置位置,0出现的次数和1出现的次数。然后,枚举分界点,通过前缀和算出把前面全部变成0,后面全部变成1所需要操作的次数和把前面的1全部变为0,全部0全部变为1的次数,两个取最小值作为ans[i],然后,取全体ans[i]的最小即可。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
const int maxn=1e3+10;
int t;
string str;
int s1[maxn];
int s2[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
clock_t c1 = clock();
//===========================================================
read(t);
while(t--){
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
cin>>str;
int n=str.length()-1;
int cnt1=0,cnt0=0;
rep(i,0,str.length()-1){
if(i==0){
s1[i]=(str[i]=='0');
s2[i]=(str[i]=='1');
}
else{
s1[i]=s1[i-1]+(str[i]=='0');
s2[i]=s2[i-1]+(str[i]=='1');
}
}
int ans=inf;
rep(i,0,str.length()-1){
ans=min(ans,min(s1[i]+s2[n]-s2[i],s2[i]+s1[n]-s1[i]));
}
write(ans),putchar('\n');
}
//===========================================================
std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
C - Game On Leaves
这题不算很难,想清楚的话。。
若一开始,x就已经是叶子节点,那当然是谁先出手谁就赢了。
若x一开始并不是叶子节点,那么,若有一个人让他变成了叶子节点,那这个人必输,因此,最优的出手应该是一直保持着x节点有两条边连着,那么,肯定先摘掉其他的所有节点,直到只剩下三个(x本身+两个和他相连的),这时候,谁先出手,谁就输,所以,判断下n-3的次数,算出剩下三个节点时谁先出手,另一方就赢了。
再衍生一下:n-3的奇偶性和n是相反的,所以,直接判断n奇偶性就行了。
因此,总结下:算下x点的度,如果x是根节点直接输出。否则,根据n的奇偶性判断。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
const int maxn=1e3+10;
int deg[maxn];
int t;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
clock_t c1 = clock();
//===========================================================
read(t);
while(t--){
memset(deg,0,sizeof(deg));
int n,x;
read(n),read(x);
rep(i,1,n-1){
int a,b;
read(a),read(b);
deg[a]++;
deg[b]++;
}
if(deg[x]==1||deg[x]==0){
puts("Ayush");
continue;
}
if((n-2)%2==0){
puts("Ayush");
}
else{
puts("Ashish");
}
}
//===========================================================
std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
E - Tree Shuffling
这道题。。还是得借助大佬题解了Orz
这道题说的好像有点恐怖,但是稍微整理一下就容易很多了。
每个节点有当前状态b[i]和目标状态c[i](b[i]到c[i]是0到1之间的互换),我们能做的操作是在一个子树中,以根节点价值*交换的节点数的代价,交换这些节点的当前状态,最终令整棵树的所有节点达到目标状态。我们会发现:对于任何一个子树,他们交换的代价,可以是(子树的根节点或其祖先的价值)交换次数,根据贪心原则,(子树的根节点或其祖先的价值)肯定选最小的,所以,我们可以有这样的思路:
从根节点(1)开始dfs,每次统计每个以每个节点为根的子树中需要0->1和1->0的节点个数。统计之后,用节点及其祖先中最小的花费a[i]去交换该子树中全部能在该子树中完成交换的节点数(其实就是2min(0->1的数量,1->0的数量)),这样,就能用最小的花费完成这些交换。
PS:为什么不是回溯到上面的几级节点再交换呢?因为深度越深,可选择的a[i]更多,更可能能找到小的。
记得更新下还是需要交换的节点的数量。具体看代码。
include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define AC return 0;
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
const int maxn=2e5+10;
int a[maxn],b[maxn],c[maxn];
ll ztoo[maxn],otoz[maxn];
ll dp[maxn];
int n;
struct Edge{
int to,next;
}e[maxn<<1];
int cnt,head[maxn];
void add(int x,int y){
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
ll ans=0;
void dfs(int u,int fa,int mc){
ll tmp=0;
if(b[u]!=c[u]){//加入当前节点的情况
if(b[u]==0){
ztoo[u]=1;
}
else{
otoz[u]=1;
}
}
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dfs(v,u,min(mc,a[v]));//将祖先中最小的a[i]传下去
//更新当前子树的情况
otoz[u]+=otoz[v];
ztoo[u]+=ztoo[v];
}
ans+=mc*min(otoz[u],ztoo[u])*2;//用最小的花费交换,更新答案
int dec=min(otoz[u],ztoo[u]);//更新仍然需要交换的节点数
otoz[u]-=dec;
ztoo[u]-=dec;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
clock_t c1 = clock();
//===========================================================
read(n);
memset(head,-1,sizeof(head));
rep(i,1,n) read(a[i]),read(b[i]),read(c[i]);
rep(i,1,n-1){
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
dfs(1,-1,a[1]);
if(otoz[1]||ztoo[1]){//若到了根节点依然没法交换完,说明无法完成交换,输出-1
write(-1);
}
else{
write(ans);
}
//===========================================================
std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
AC
}