K倍区间
题解及代码
/*求区间[l,r]的和是k的倍数的个数。求区间和,我们可以通过前缀和来求出。我们规定sum[i]表示第1个元素到第i个元素的和。
那么sum[r] - sum[l-1]就是区间[l,r]的和。区间[l,r]的和是k的倍数即(sum[r] - sum[l-1])%k == 0 即sum[r]%k == sum[l-1]%k
那么,我们求出每个前缀和,在求的过程中取模,两个相等的前缀和就能组成一个k倍区间。
我们用一个数组cnt[i]表示当前位置之前,前缀和取模后等于i的个数。
如果当前前缀和sum%k==i,那么,当前位置与之前所有(sum%k==i)都能匹配,所有总个数要加上cnt[i].
*/
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
const int maxn=100005;
int pre[maxn];
int cnt[maxn];
int n,k;
int a[maxn];
int main(){
freopen("1.txt","r",stdin);
cin>>n>>k;
mem(pre,0);
mem(cnt,0);
int sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
pre[i]=(pre[i-1]+a[i])%k;
sum+=cnt[pre[i]];
cnt[pre[i]]++;
}
cout<<sum+cnt[0]<<endl;//要记得加上本身一个数字就能被整除的数
return 0;
}
承压计数
X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。
每块金属原料的外形、尺寸完全一致,但重量不同。
金属材料被严格地堆放成金字塔形。
7
5 8
7 8 8
9 2 7 2
8 1 4 9 1
8 1 8 8 4 1
7 9 6 1 4 5 4
5 6 5 5 6 9 5 6
5 5 4 7 9 3 5 5 1
7 5 7 9 7 4 7 3 3 1
4 6 4 5 5 8 8 3 2 4 3
1 1 3 3 1 6 6 5 5 4 4 2
9 9 9 2 1 9 1 9 2 9 5 7 9
4 3 3 7 7 9 3 6 1 3 8 8 3 7
3 6 8 1 5 3 9 5 8 3 8 1 8 3 3
8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9
8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4
2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9
7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6
9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3
5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9
6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4
2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4
7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6
1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3
2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8
7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9
7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6
5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
其中的数字代表金属块的重量(计量单位较大)。
最下一层的X代表30台极高精度的电子秤。
假设每块原料的重量都十分精确地平均落在下方的两个金属块上,
最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。
电子秤的计量单位很小,所以显示的数字很大。
工作人员发现,其中读数最小的电子秤的示数为:2086458231
请你推算出:读数最大的电子秤的示数为多少?
处理完的数据
7
5 8
7 8 8
9 2 7 2
8 1 4 9 1
8 1 8 8 4 1
7 9 6 1 4 5 4
5 6 5 5 6 9 5 6
5 5 4 7 9 3 5 5 1
7 5 7 9 7 4 7 3 3 1
4 6 4 5 5 8 8 3 2 4 3
1 1 3 3 1 6 6 5 5 4 4 2
9 9 9 2 1 9 1 9 2 9 5 7 9
4 3 3 7 7 9 3 6 1 3 8 8 3 7
3 6 8 1 5 3 9 5 8 3 8 1 8 3 3
8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9
8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4
2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9
7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6
9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3
5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9
6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4
2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4
7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6
1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3
2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8
7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9
7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6
5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1
题解及代码
/*
其实就是类似杨辉三角
*/
double dp[40][40];
int main(){
freopen("1.txt","r",stdin);
for(int i=0;i<40;i++){
for(int j=0;j<40;j++)dp[i][j]=0;
}
for(int i=1;i<30;i++){
for(int j=1;j<=i;j++)cin>>dp[i][j];
}
for(int i=2;i<=30;i++){
for(int j=1;j<=i;j++){
dp[i][j]+=dp[i-1][j-1]/2+dp[i-1][j]/2;
}
}
double y=mod;
double ma=0;
for(int i=1;i<=30;i++){
y=min(y,dp[30][i]);
ma=max(ma,dp[30][i]);
}
cout<<y<<" "<<ma<<endl;
double ans=ma*(2086458231.0/y);
printf("%lf\n",ans);
return 0;
}
分巧克力
儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
1. 形状是正方形,边长是整数
2. 大小相同
例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?
输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
输入保证每位小朋友至少能获得一块1x1的巧克力。
输出
输出切出的正方形巧克力最大可能的边长。
样例输入:
2 10
6 5
5 6
样例输出:
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
题解及代码
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
const int mod=3e9+7;
const int maxn=1e5+7;
//一开始以为dp,后来发现数据范围太大了
//看题解介绍是二分模板题。。。
//二分边长,然后去判断数量够不够
struct node{
int h,w;
node(int H,int W):h(H),w(W){}
node(){}
};
node a[maxn];
int n,k;
bool judge(int m){
int sum=0;
for(int i=0;i<n;i++){
int x=a[i].h/m;
int y=a[i].w/m;
sum+=x*y;
}
return sum>=k;
}
int solve(){
int l=1,r=100001,mid;
int ans=-1;
while(l<r){
mid=(l+r)/2;
if(judge(mid)){
ans=mid;
//cout<<"mid="<<mid<<endl;
l=mid+1;
}
else r=mid;
}
return ans;
}
int main(){
freopen("1.txt","r",stdin);
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>a[i].h>>a[i].w;
}
cout<<solve()<<endl;
return 0;
}
包子凑数
题解及代码
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=105;
const int mod=maxn*maxn+20;
int a[maxn];
bool vis[maxn*(maxn+1)];
int main(){
int n;
cin>>n;
int gcdd=0;
mem(vis,0);
for(int i=0;i<n;i++){
cin>>a[i];
vis[a[i]]=1;
gcdd=__gcd(a[i],gcdd);
}
if(gcdd!=1)printf("INF\n");
else{
//我觉得可以认为是筛法,也可以认为是完全背包
for(int i=0;i<n;i++){
for(int j=0;j+a[i]<mod;j++){
if(vis[j])vis[j+a[i]]=1;
}
}
int ans=0;
for(int j=mod-1;j>0;j--){
if(!vis[j])ans++;
}
printf("%d\n",ans);
}
return 0;
}
日期问题
题解及代码
/*
写一个日期的类会好很多
*/
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
const int maxn=100005;
//1 3 5 7 8 10 12 上半年单数,下半年双数
//Date结构体!!!
int mon_day[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
struct Date{
int year,month,day;
Date(int y,int m,int d):year(y),month(m),day(d){}
Date(){}
bool isLeap(){
return (year%400==0)||(year%4==0&&year%100!=0);
}
bool vaild(){
if(year<1960||year>2059)return false;
if(month<1||month>12)return false;
if(day<1)return false;
if(isLeap()){
if(month==2)return day<=mon_day[month]+1;
return day<=mon_day[month];
}
else return day<=mon_day[month];
}
bool operator <(const Date b)const{
if(year==b.year){
if(month==b.month){
return day<b.day;
}
return month<b.month;
}
return year<b.year;
}
void printDate(){
printf("%d-%02d-%02d\n",year,month,day);
}
};
set<Date>que;
void insertDa(int y,int m,int d){
Date dd(y,m,d);
if(dd.vaild()){
que.insert(dd);
}
}
void solve(){
int y,m,d;
scanf("%d/%d/%d",&y,&m,&d);
int y1=1900;
int y2=2000;
//年y月m日d
insertDa(y+y1,m,d);
insertDa(y+y2,m,d);
//月y日m年d
insertDa(d+y1,y,m);
insertDa(d+y2,y,m);
//日y月m年d
insertDa(d+y1,m,y);
insertDa(d+y2,m,y);
for(auto it:que){
it.printDate();
}
}
int main(){
solve();
return 0;
}
方格分割
标题:方格分割
6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。
如图:p1.png, p2.png, p3.png 就是可行的分割法。
试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法。
请提交该整数,不要填写任何多余的内容或说明文字。
题解及代码
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
int sum=0;
bool vis[10][10];
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
///边线是交汇点才是标号处,格子不是标号
void dfs(int x,int y){
if(x==0||y==0||x==6||y==6){//线走到边界就没有其他平移的必要了,对格子数不产生影响
sum++;
return;///代表结束递归!!!!
}
for(int i=0;i<4;i++){
int xx=x+d[i][0];
int yy=y+d[i][1];
if(!vis[xx][yy]){
vis[xx][yy]=1;
vis[6-xx][6-yy]=1;
dfs(xx,yy);
vis[xx][yy]=0;
vis[6-xx][6-yy]=0;
}
}
}
int main(){
sum=0;
mem(vis,0);
vis[3][3]=1;
dfs(3,3);
cout<<sum/4<<endl;//旋转对称属于一种方案(4个方向嘛)
return 0;
}