noip2016普及组 题解

时间:2022-12-16 23:25:14

T1

大水题,不解释 上考场代码
#include <algorithm>
#include
<cstdio>
using namespace std;
int main() {
freopen(
"pencil.in","r",stdin);
freopen(
"pencil.out","w",stdout);
int n,Min = 0x7fffffff;
scanf(
"%d",&n);
for (int i = 1;i <= 3;i++) {
int number,money,count;
scanf(
"%d%d",&number,&money);
count
= n/number;
if (n%number) count++; //count为需要买的包数
Min = min(Min,count*money); //取最小的
}
printf(
"%d",Min);
return 0;
}

 

T2

简单的模拟,生成date1到date2的所有日期,判断是否回文
上考场代码
#include <cstdio>
int m[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
inline
bool check(int date) { //判断是否回文
int t[9];
t[
0] = 0;
while (date) {
t[
++t[0]] = date%10;
date
/= 10;
}
for (int i = 1;i <= 4;i++)
if (t[i] != t[8-i+1]) return false;
return true;
}
inline
int next(int i) { //生成下一个日期
int year,month,day;
day
= (i%10)+((i/10%10)*10); //取出日
i /= 100;
month
= (i%10)+((i/10%10)*10); //取出月
i /= 100;
year
= (i%10)+((i/10%10)*10)+((i/100%10)*100)+i/1000*1000; //取出年
if ((!(year%4) && year%100) || !(year%400)) m[2] = 29; //判断是否为闰年
day++; //下一天
if (day == m[month]+1) { //若到了月底,则变到下一月
day = 1;
month
++;
}
if (month == 13) { //若到了年底,则变到下一年
month = 1;
year
++;
}
return day+month*100+year*10000; //把年月日变成8位数字
}
int main() {
freopen(
"date.in","r",stdin);
freopen(
"date.out","w",stdout);
int date1,date2,ans = 0;
scanf(
"%d%d",&date1,&date2);
for (int i = date1;i <= date2;i = next(i)) //生成date1到date2的所有日期
if (check(i)) ans++; //判断是否回文
printf("%d",ans);
return 0;
}

 

T3

考场上写了个暴力模拟,70分......出来后发现还是可以做的,写个队列就行了,超出86400s的就出队70分考场代码
#include <cstring>
#include
<cstdio>
#include
<map>
using namespace std;
int n,t[100001],k[100001];
bool tmp[100001];
map
<int,int> x[100001];
int main() {
freopen(
"port.in","r",stdin);
freopen(
"port.out","w",stdout);
scanf(
"%d",&n);
for (int i = 1;i <= n;i++) {
scanf(
"%d%d",&t[i],&k[i]);
for (int j = 1;j <= k[i];j++) scanf("%d",&x[i][j]);
int L = 1,R = i,pos = i;
while (L <= R) {
int mid = (L+R)>>1;
if (t[mid] > t[i]-86400) {
pos
= mid;
R
= mid-1;
}
else L = mid+1;
}
int ans = 0;
memset(tmp,
false,sizeof(tmp));
for (int j = pos;j <= i;j++)
for (int l = 1;l <= k[j];l++)
if (!tmp[x[j][l]]) {
ans
++;
tmp[x[j][l]]
= true;
}
printf(
"%d\n",ans);
}
return 0;
}

 

100分代码
#include <cstdio>
#include
<queue>
#include
<map>
using namespace std;
int n,ans = 0,vis[100001];
struct Queue { int t,x; };
queue
<Queue> Q;
inline
int read(int &x) { //读入优化
char ch;
while ((ch = getchar()) < '0' || ch > '9');
x
= ch-'0';
while ((ch = getchar()) >= '0' && ch <= '9') x = x*10+ch-'0';
}
int main() {
freopen(
"port.in","r",stdin);
freopen(
"port.out","w",stdout);
read(n);
for (int i = 1;i <= n;i++) {
int t,k;
read(t),read(k);
for (int i = 1,x;i <= k;i++) {
read(x);
if (!vis[x]) ans++; //若这个乘客是其他国籍,则统计
vis[x]++; //统计
Q.push((Queue){t,x}); //加入队列
}
while (true) { //把86400以外的排除
Queue head = Q.front();
if (t-86400+1 <= head.t && head.t <= t) break;
else {
vis[head.x]
--;
if (!vis[head.x]) ans--;
Q.pop();
}
}
printf(
"%d\n",ans);
}
return 0;
}

 

T4

考场上想不出,于是打了个暴力,40分......40分考场暴力代码
#include <cstdio>
int main() {
int n,m,x[40001],ans[40001][4];
scanf(
"%d%d",&n,&m);
for (int i = 1;i <= m;i++) scanf("%d",&x[i]);
for (int a = 1;a <= m;a++)
for (int b = 1;b <= m;b++)
if (a != b)
for (int c = 1;c <= m;c++)
if (c != a && c != b && (double)x[b]-(double)x[a] < (double)((double)x[c]-(double)x[b])/3.0)
for (int d = 1;d <= m;d++)
if (d != a && d != b && d != c && x[a] < x[b] && x[b] < x[c] && x[c] < x[d] && x[b]-x[a] == 2*(x[d]-x[c])) {
ans[a][
0]++;
ans[b][
1]++;
ans[c][
2]++;
ans[d][
3]++;
}
for (int i = 1;i <= m;i++) printf("%d %d %d %d\n",ans[i][0],ans[i][1],ans[i][2],ans[i][3]);
return 0;
}

 

4重循环是用不到n的,没有白给的条件,没有没用的数据!!!
我们可以把这4个数看作是个数轴上的点,根据题目给的条件,可知AB=2*CD,BC>6*CD,AD>9*CDnoip2016普及组 题解那么,我们只需要确定D,就可以确定C点,然后再找AB。我们也可以通过找C来确定ABD。100分代码
#include <cstdio>
int n,m,x[40001],vis[15001],a[15001],b[15001],c[15001],d[15001];
int main() {
freopen(
"magic.in","r",stdin);
freopen(
"magic.out","w",stdout);
scanf(
"%d%d",&n,&m);
for (int i = 1;i <= m;i++) {
scanf(
"%d",&x[i]);
vis[x[i]]
++; //把所有数记在数轴上
}
for (int i = 1;i <= n/9;i++) { //枚举CD的长度
int sum = 0;
for (int j = i*9+2;j <= n;j++) {
  sum
+= vis[j-(9*i+1)]*vis[j-(9*i+1)+2*i];
   d[j]
+= sum*vis[j-i];
   c[j
-i] += sum*vis[j];
   }
  sum
= 0;
  
for (int j = n-(9*i+1);j >= 1;j--) { //枚举CD两点,确定AB的个数
  sum += vis[j+(9*i+1)]*vis[j+(9*i+1)-i];
  a[j]
+= sum*vis[j+2*i];
  b[j
+2*i] += sum*vis[j];
  }
}
for (int i = 1;i <= m;i++) printf("%d %d %d %d\n",a[x[i]],b[x[i]],c[x[i]],d[x[i]]);
return 0;
}