A. Not Wool Sequences
给你两个数:n和m,要求用0~2^m-1这些数不重复的组成一个长度为n的序列,使得序列中不存在这样的子序列:
(1 ≤ l ≤ r ≤ n) ,,
表示 x 异或 y
现在问,总共有多少这样的序列
好吧,这么一个水题硬是花了半个小时才AC
思考方向:固定m,考虑长度为 n-1 和长度为 n 的序列之间的关系,就会发现一个神奇的规律,至于是什么,自己找吧,很有意思
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <ctime>
#include <cmath>
#include <functional>
#include <stdexcept>
#include <algorithm>
#include <iostream>
#include <utility>
#include <sstream>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
typedef double DB;
typedef unsigned long long ULL;
typedef unsigned int Uint;
const int INT_INF=0x3fffffff;
const int MOD=1000000009;
const int N=100001;
const int E=100001;
const DB EPS=1e-9;
const DB PI=3.14159265358979323846;
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int, int> PII;
#define PB push_back
#define MP make_pair
#define MH make_heap
#define PH push
LL n,m;
LL ans;
LL power(LL n, LL p)
{
if(p==0) return 0;
LL odd=1;
while(p>1)
{
if(p&1) odd=(odd*n)%MOD;
n=(n*n)%MOD;
p/=2;
}
return (odd*n)%MOD;
}
int main()
{
scanf("%d%d", &n, &m);
LL ans=1;
LL temp=power(2, m);
for(int i=1; i<=n; i++)
{
ans=(ans*(temp-i))%MOD;
}
printf("%I64d\n", ans);
return 0;
}
B. Boring Partition
给你一串数,让你给他们分成两份,现在定义一个函数:
f(x,y):x+y, x和y在同一个集合中
x+y+h ,x和y不在一个集合中
现在要你找出一个分配方式,使得f_max-f_min 最小
贪心,要么把最小的和其他的数放在一起,要么把最小的和其他的分开,当时看反复看了半小时,硬是没看懂题意
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <ctime>
#include <cmath>
#include <functional>
#include <stdexcept>
#include <algorithm>
#include <iostream>
#include <utility>
#include <sstream>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
typedef double DB;
typedef unsigned long long ULL;
typedef unsigned int Uint;
const int INT_INF=0x3fffffff;
const int MOD=1000000007;
const int N=100005;
const int E=100001;
const DB EPS=1e-9;
const DB PI=3.14159265358979323846;
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int, int> PII;
#define PB push_back
#define MP make_pair
#define MH make_heap
#define PH push
struct data
{
int x, id;
} a[N];
int n, h;
int belong[N];
bool cmp(data a, data b)
{
return a.x<b.x;
}
int main()
{
scanf("%d%d", &n, &h);
for(int i=1; i<=n; i++)
{
scanf("%d", &a[i].x);
a[i].id=i;
}
for(int i=1; i<=n; i++)
belong[i]=1;
sort(a+1, a+1+n, cmp);
int ans1=a[n].x+a[n-1].x-a[1].x-a[2].x;
int ans2=max(a[n].x+a[n-1].x, a[n].x+a[1].x+h)-min(a[2].x+a[3].x, a[1].x+a[2].x+h);
if(ans2<ans1)
{
belong[a[1].id]=2;
ans1=ans2;
}
printf("%d\n", ans1);
for(int i=1; i<=n; i++)
{
printf("%d", belong[i]);
if(i==n) printf("\n");
else printf(" ");
}
return 0;
}
C. World Eater Brothers
题意就是给你一棵树,初始时树中的边全是有向边,现在两个SB想占领这棵树,占领了一个节点,就把所有这个节点能够到达的节点全部占领了,如果需要占领更多的节点,就需要改变某些边的方向,使得能从占领的节点出发前往其他的节点,现在问你,这两个人选择哪两个节点用来占领这棵树,使得总共改变的边数量最少
可以这样想,这两个人占领这棵树后一定是把这棵树分成了两个部分,每个部分分别是一棵树,现在就转变成了怎么在一棵树上选择一个节点占领,使得要占领这棵树总共翻转的边最少,这就两遍DFS就行了,暂且归类为树形DP吧,至于这两个人怎么分这棵树,直接暴力枚举,然后取代价最小的就行了,幸好当时这道题做出来了,不然就滚回Div2了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <ctime>
#include <cstdlib>
#include <stack>
#include <map>
#include <set>
#include <list>
#define MP make_pair
#define PB push_back
#define INT_INF 0x3fffffff
#define LL_INF 0x3fffffffffffffff
#define EPS 1e-12
#define MOD 1000000007
#define PI 3.14159265358979323846
#define N 200010
#define E 400010
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned int Uint;
typedef double DB;
struct Edge
{
int st,en,val,next;
} edge[E];
int head[N] , tot;
int f[N];
void add_edge(int st,int en,int val)
{
edge[tot].st=st;
edge[tot].en=en;
edge[tot].val=val;
edge[tot].next=head[st];
head[st]=tot++;
}
void dfs1(int u,int pre, int split_edge)
{
f[u]=0;
for(int e=head[u]; e!=-1; e=edge[e].next)
{
int v=edge[e].en;
if(e==split_edge || e==split_edge+1) continue;
if(v==pre) continue;
f[u]+=edge[e].val;
dfs1(v, u, split_edge);
f[u]+=f[v];
}
}
vector<int> res;
int ans;
void dfs2(int u,int pre,int now, int split_edge)
{
if(now+f[u]<ans)
{
res.clear();
ans=now+f[u];
res.PB(u);
}
else if(now+f[u]==ans) res.PB(u);
for(int e=head[u]; e!=-1; e=edge[e].next)
{
int v=edge[e].en;
if(e==split_edge || e==split_edge+1) continue;
if(v==pre) continue;
int cnt=now+f[u]-f[v];
if(edge[e].val==0) cnt++;
if(edge[e].val==1) cnt--;
dfs2(v,u,cnt,split_edge);
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(head,-1,sizeof(head));
tot=0;
for(int i=1,a,b; i<n; i++)
{
scanf("%d%d",&a,&b);
add_edge(a,b,0);
add_edge(b,a,1);
}
int Min=INT_INF;
for(int e=0; e<tot; e++)
{
if(edge[e].val==1) continue;
int temp=0;
dfs1(edge[e].st, -1, e);
ans=INT_INF;
res.clear();
dfs2(edge[e].st, -1, 0, e);
temp+=ans;
dfs1(edge[e].en, -1, e);
ans=INT_INF;
res.clear();
dfs2(edge[e].en, -1, 0, e);
temp+=ans;
if(temp<Min) Min=temp;
}
if(n==1) Min=0;
printf("%d\n", Min);
}
return 0;
}
D和E没有想法。。。
总的来说,这次没能读懂题意是最大的失误,还有就是水题出的太慢了,人家A题直接秒了,而我还要花半个小时才能够搞出来