【小结】:
比赛时只完成了3个题,但是杨哥哥已经完成了7个题,而且有些题补题补得我脑阔疼,终于发现差距在哪里了,差距就是你在刷题的时候别人也在刷题,你在玩的时候别人也在刷题,这个差距不可收缩吗?自己要提一下效率上来不然就慢别人好几步了。
C题:构造题:
题目是,给n×n个数字,然后让你构造出,N维回文矩阵出来。
【题解】:
分奇偶性情况讨论:
首先比较容易解决的是偶数情况,因为发现偶数上下均需要对称,说明:每一个位置都需要4个,所以所有数字都必须是4的倍数,不然就无法构造,然后只要对于左上角填上去,排序后每隔4个来填。
然后奇数情况:
你发现奇数是在原来的基础上发生了变化,多了中间的一行和一列。
注意的细节:
1、必须要有(n/2)*(n/2)个 4的倍数。首先填补,主要是(n/2)*(n/2)不要少了括号,不然左结合你就错了一遍了。
2、如果填补完后,中间的缝隙,用2的倍数来填补,所以说,之前用4 的倍数如果有剩下来的必须转化一下。
个人代码比较长:
#include
#include
using namespace std;
const int N=500;
const int M=25;
int a[N];
int vis[N<<2];
int b[N][N];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i=4){
int t=vis[i]/4;
cnt+=t;
vis[i]-=4*t;
while(t--){
c[0][t1++]=i;
}
}
if(vis[i]>=2){
c[1][t2++]=i;
}
}
if(tot>1||(n/2)*(n/2)>cnt){
//printf("%d %d %d\n",tot,(n/2)*(n/2),cnt);
printf("NO\n");
}else{
printf("YES\n");
b[n/2][n/2]=f;
int cur=0;
//for(int i=0;it2&&cur<=t1){
c[1][t2]=c[1][t2+1]=c[0][cur];
t2+=2;
cur++;
}
//for(int i=0;i
【题意】:
给你n杯咖啡,然后可以有ai的动力写稿子ai页,然后有m页稿子,如果连续和咖啡,第二杯页数就会-1,然后第三杯就会-2/、如此类推,然后问你最少多少天可以把稿子赶出来。
【题解】:
赛后一直以为是分组来写,后来发现如果出现很多咖啡很小的时候这个就不可行了。然后看到别人的做法都是二分写的,你就明白为什么二分了,二分天数,每杯咖啡一直放,按从大到小一直放,因为可能出现 放到后面 可能会出现负数,你就判断一下,最后的总和>=m true.然后看看题解的写法。
题解的写法:
#include
using namespace std;
int n, m;
vector a;
bool can(int i) {
long long sum = 0; // there can be a bug
for (int j = 0; j < n; ++j) {
sum += max(a[j] - j / i, 0);
}
return sum >= m;
}
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
cin >> n >> m;
a = vector(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
sort(a.rbegin(), a.rend());
int l = 1, r = n;
while (r - l > 1) {
int mid = (l + r) >> 1;
if (can(mid)) r = mid;
else l = mid;
}
if (can(l)) cout << l << endl;
else if (can(r)) cout << r << endl;
else cout << -1 << endl;
return 0;
}
自己参考别人的写法:
#include
using namespace std;
typedef long long ll;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
ll n,m,a[N];
bool check(ll mid){
ll t=0;
for(int i=0;i=m?true:false;
}
ll cmp(ll a,ll b){
return a>b;
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i=0;i>1;
if(check(mid)){
ans=mid;
R=mid-1;
}else{
L=mid+1;
}
}
printf("%lld\n",ans);
return 0;
}
【题意】:
题意为:让你构造出n对出来,然后每一对中数字必须是[ 1, k ],然后最后实现的n对出来:
注意每一对有要求:
1、不存在两对完全相同,即(ai,bi)!=(aj,bj) (i!=j)
2、不存在 一对里相同,即(ai,bi) (ai!=bi)
3、相邻之间不能出现连续的第一个相同或这第二个相同 。
即(1,2) (1,×) ,或者(1,2)(×,2)
官方题解是第一维都是1-K,第二维有意错开即可.
#include
using namespace std;
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int n, k;
cin >> n >> k;
if (n > k * 1ll * (k - 1)) {
cout << "NO" << endl;
} else {
cout << "YES" << endl;
int cur = 0;
for (int i = 0; i < n; ++i) {
cur += (i % k == 0);
cout << i % k + 1 << " " << (cur + i % k) % k + 1 << endl;
}
}
return 0;
}
成浩哥的做法:
就是跑一个矩阵,这个矩阵就是一直跑反向斜对角线。
#include
using namespace std;
typedef long long ll;
int main()
{
ll n,k;
scanf("%lld%lld",&n,&k);
if(n>(k-1)*k){
printf("NO\n");
}else{
printf("YES\n");
ll x=1,y=1;
for(ll i=1;i<=n;i++){
x++;y--;
if(x==y){
i--;continue;
}
if(y==0){
y=x;x=1;
}
if(y>k||x>k){
i--;continue;
}
printf("%lld %lld\n",x,y);
}
}
return 0;
}
【题意】:
给你一棵树,然后每一个节点都有相应的颜色,分别为无色,红色,蓝色,问你切断哪里可以把树分为红色和蓝色两个部分。
【官方做法】:
用DFS搜索,然后把子树的情况相加,只是统计 全部红色都有 而没有蓝色,和全部蓝色没有红色的情况。
#include
#define forn(i, n) for (int i = 0; i < int(n); i++)
using namespace std;
const int N = 300 * 1000 + 13;
int n;
int a[N];
vector g[N];
int red, blue;
int ans;
pair dfs(int v, int p = -1){
int r = (a[v] == 1), b = (a[v] == 2);
for (auto u : g[v]) if (u != p){
auto tmp = dfs(u, v);
ans += (tmp.first == red && tmp.second == 0);
ans += (tmp.first == 0 && tmp.second == blue);
r += tmp.first;
b += tmp.second;
}
return make_pair(r, b);
}
int main() {
int n;
scanf("%d", &n);
forn(i, n){
scanf("%d", &a[i]);
red += (a[i] == 1);
blue += (a[i] == 2);
}
forn(i, n - 1){
int v, u;
scanf("%d%d", &v, &u);
--v, --u;
g[v].push_back(u);
g[u].push_back(v);
}
ans = 0;
dfs(0);
printf("%d\n", ans);
return 0;
}
【杨哥哥做法】:
我发现杨哥哥真的强,强在哪里呢,可以把问题剖析得很好,用第一个dfs把全部颜色的情况往根节点进行统计,然后用dfs2来历遍所有树干,看一下改变断了是否可以把所有的红蓝分开。
#include
using namespace std;
const int N=3e5+10;
vectorG[N];
int sum[N][3];
int a[N],n,ans=0;
void dfs1(int u,int fa){
sum[u][a[u]]++;
for(auto v:G[u]){
if(v==fa) continue;
dfs1(v,u);
for(int j=0;j<3;j++){
sum[u][j]+=sum[v][j];
}
}
}
void dfs2(int u,int fa){
for(auto v:G[u]){
if(v==fa) continue;
dfs2(v,u);
if(sum[v][1]==0&&sum[v][2]==sum[1][2]){
ans++;
}else if(sum[v][2]==0&&sum[v][1]==sum[1][1]){
ans++;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1,u,v;i