【题目链接】
Problem A group
我们发现,如果存在三个人互相不认识的情况,则输出“no”,否则输出“yes”
【代码】
#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
int i,j,k,n,u;
bool g[MAXN][MAXN];
bool flag;
template <typename T> inline void read(T &x)
{
int f = 1; x = 0;
char c = getchar();
for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
x *= f;
}
template <typename T> inline void write(T x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9) write(x/10);
putchar(x%10+'0');
}
template <typename T> inline void writeln(T x)
{
write(x);
puts("");
}
int main() {
while (scanf("%d",&n) != EOF)
{
flag = false;
memset(g,false,sizeof(g));
for (i = 1; i <= n; i++)
{
while (scanf("%d",&u) && u) g[i][u] = true;
}
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
for (k = 1; k <= n; k++)
{
if (i == j || i == k || k == j) continue;
if ((!g[i][j] || !g[j][i]) && (!g[i][k] || !g[k][i]) && (!g[k][j] || !g[j][k]))
flag = true;
}
}
}
if (flag) printf("NO\n");
else printf("YES\n");
}
return 0;
}
Problem B flyer
Part A : 部分分算法
1.1 对于30%的数据,Max(Ci)≤10000,N≤1000,那么,暴力模拟即可
1.2 20%数据满足Ai=Ci,那么,只需用stl库里的map统计答案,即可
1.3 综合前两种部分分算法,期望得分 : 50
1.4 根据异或运算的性质,我们知道两个相同的数异或会抵消,那么我们只需每次枚举那些位置获得了物品,将这些位置
异或,最后,如果异或后的值为0,则无解,否则有解,统计获得了多少物品我们依然用stl库里的map计算,期望得分 :70
Part B : 满分算法:
利用题目中的条件,最多只有一个人获得奇数个物品,那么如果在区间[1,2^32]每个人获得物品的累加和为奇数,则有 解,否则无解
那么,我们考虑 : 对于区间[l,r],我们将它分成[l,mid]和[mid+1,r],如果区间[l,r]每个人获得物品累加和为奇数,则说明
答案在这个区间,否则,答案在区间[mid+1,r]中,那么,我们就可以通过这种二分的方式,求出要求的位置,时间复杂度 :
O(Nlog(N))
【代码】
#include<bits/stdc++.h>
using namespace std;
#define MAXN 20010
int i,n;
long long mx,l,r,mid;
long long a[MAXN],b[MAXN],c[MAXN];
inline long long calc(long long l,long long r)
{
int i;
long long k,ans = 0,L,R;
for (i = 1; i <= n; i++)
{
if (a[i] > r || c[i] < l) continue;
if (l >= a[i])
{
if ((l - a[i]) % b[i] == 0) k = (l - a[i]) / b[i];
else k = (l - a[i]) / b[i] + 1;
} else k = 0;
L = a[i] + k * b[i];
R = min(r,c[i]);
if (L > R) continue;
ans += (R - L) / b[i] + 1;
}
return ans;
}
int main()
{
mx = 1;
for (i = 1; i <= 32; i++) mx *= 2;
while (scanf("%d",&n) != EOF)
{
for (i = 1; i <= n; i++) scanf("%lld%lld%lld",&a[i],&c[i],&b[i]);
if (calc(1,mx) % 2 == 0) printf("DC Qiang is unhappy.\n");
else
{
l = 1; r = mx;
while (l <= r)
{
mid = (l + r) >> 1;
if (calc(l,mid) % 2 == 1) r = mid - 1;
else l = mid + 1;
}
printf("%lld %lld\n",l,calc(l,l));
}
}
return 0;
}
Problem C Weight
Part A : 部分分算法
1.1 对于每次询问DFS,期望得分 : 30
1.2 先处理所有可以称出的物品的重量,将它放入一张哈希表中,每次询问只需查询哈希表中有没有这个数,时间复杂度
大约是O(3^n),期望得分 : 70
Part B : 满分算法
算法1.2起到了引导思考的作用,我们发现如果按1.2做,时间复杂度最劣时达到O(3^24)
考虑使用折半搜索(中途相遇法),将每次询问的数 a 分成 x + y,x在前半部分中,y在后半部分中,那么,我们只需
先求出前半和后半部分能称出物品的重量,每次询问,在前一半数中找到x,如果后一半数中有a - x这个数,输出yes,否则
输出no,显然可以二分,时间复杂度 : O(3^(N/2)+Mlog(3^(N/2)))
【代码】
#include<bits/stdc++.h>
using namespace std;
#define MAXN 25
int i,j,n,m,len;
long long w,t;
long long a[MAXN];
vector<long long> x,y;
bool flag;
template <typename T> inline void read(T &x)
{
int f = 1; x = 0;
char c = getchar();
for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
x *= f;
}
template <typename T> inline void write(T x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9) write(x/10);
putchar(x%10+'0');
}
template <typename T> inline void writeln(T x)
{
write(x);
puts("");
}
inline bool search(long long x)
{
int l = 0,r = y.size() - 1,mid;
while (l <= r)
{
mid = (l + r) >> 1;
if (y[mid] == x) return true;
if (x < y[mid]) r = mid - 1;
else l = mid + 1;
}
return false;
}
int main()
{
read(n); read(m);
for (i = 1; i <= n; i++) read(a[i]);
x.push_back(0);
for (i = 1; i <= n / 2; i++)
{
len = x.size();
for (j = 0; j < len; j++)
{
x.push_back(x[j]+a[i]);
x.push_back(x[j]-a[i]);
}
}
y.push_back(0);
for (i = n / 2 + 1; i <= n; i++)
{
len = y.size();
for (j = 0; j < len; j++)
{
y.push_back(y[j]+a[i]);
y.push_back(y[j]-a[i]);
}
}
sort(x.begin(),x.end());
unique(x.begin(),x.end());
sort(y.begin(),y.end());
unique(y.begin(),y.end());
for (i = 1; i <= m; i++)
{
flag = false;
read(w);
for (j = 0; j < x.size(); j++)
{
t = w - x[j];
if (search(t))
{
flag = true;
break;
}
}
if (flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}