noip2016普及组 题解

GX蒟蒻第一次参加noip,考下来310分,请诸位神犇多包容

T1

大水题,不解释
上考场代码
#include 
#include 
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 
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 
#include 
#include 
using namespace std;
int n,t[100001],k[100001];
bool tmp[100001];
map 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 
#include 
#include 
using namespace std;
int n,ans = 0,vis[100001];
struct Queue { int t,x; };
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 
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*CD
noip2016普及组 题解_第1张图片
那么,我们 只需要确定D,就可以确定C点,然后再找AB。我们也可以通过找C来确定ABD。
100分代码
#include 
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;
}


你可能感兴趣的:(noip)