太久没做题了,做题做出来就是没感觉。
要么就是知道做,写不对;要么就是看不懂题,看懂了之后觉得很简单
哈夫曼树的简单模拟都不会了必须得使用C++的优先队列搞法,简直弱爆炸
————————————————————————————————————————————————————————————————
废话不多说,先来一发比赛链接
NWPU开学第一战
————————————————————————————————————————————————————————————————
A题是字符串的处理题似乎要用到kmp
C题是图论的题,暂时没思路先留空留在这,会了再说
————————————————————————————————————————————————————————————————
exgcd的基本题
注意题意的要求有两个:系数和尽量小,总砝码质量也尽量小
exgcd
上列了个exgcd的基本题链接,可以看到弱的代码
基本算法思想就不解释了,百度一大堆,注意这个题的方法。必须考虑到三种情况:
ax+by=m
-ax+by=m
ax-by=m
然后,就简单了
ll a,b,m,ansx,ansy,tot; ll x,y,g,l,r,x1,x2; ll exgcd(ll a,ll b,ll &x,ll &y){ if (a==0&&b==0) return -1; if (b==0){ x=1;y=0;return a; } ll d=exgcd(b,a%b,y,x); y-=a/b*x; return d; } int main(){ //input; while(scanf("%I64d%I64d%I64d",&a,&b,&m)!=EOF){ if (a+b+m==0) break; tot=ansx=ansy=INF; tot*=99999999; g=exgcd(a,-1*b,x,y); x*=m/g; y*=m/g; l=b/g;if (l<0) l=-1*l; r=a/g;if (r<0) r=-1*r; x1=(x%l+l)%l; y=(y%r+r)%r; x2=(m+b*y)/a; for(x=x1;x<=x2;x+=l){ y=(a*x-m)/b; if (y<0) continue; if (x+y<=ansx+ansy&&tot>=x*a+b*y){ ansx=x; ansy=y; tot=x*a+b*y; } } g=exgcd(a,b,x,y); x*=m/g; y*=m/g; l=b/g;if (l<0) l=-1*l; r=a/g;if (r<0) r=-1*r; x1=(x%l+l)%l; y=(y%r+r)%r; x2=(m+b*y)/a; for(x=x1;x<=x2;x+=l){ y=(m-a*x)/b; if (y<0) continue; if (x+y<=ansx+ansy&&tot>=x*a+b*y){ ansx=x; ansy=y; tot=x*a+b*y; } } m=-1*m; g=exgcd(a,-1*b,x,y); x*=m/g; y*=m/g; l=b/g;if (l<0) l=-1*l; r=a/g;if (r<0) r=-1*r; x1=(x%l+l)%l; y=(y%r+r)%r; x2=(m+b*y)/a; for(x=x1;x<=x2;x+=l){ y=(a*x-m)/b; if (y<0) continue; if (x+y<=ansx+ansy&&tot>=x*a+b*y){ ansx=x; ansy=y; tot=x*a+b*y; } } printf("%I64d %I64d\n",ansx,ansy); } return 0; }
熟悉前缀和的,熟悉欧拉函数的,这个题就是个模板咯
直接上代码也能懂的
可以直接打表的随便搞法
LL euler[maxn+50]; void getEuler(){ memset(euler,0,sizeof(euler)); euler[1]=1; for(int i=2;i<=1000000;i++) if (!euler[i]) for(int j=i;j<=1000000;j+=i){ if (!euler[j]) euler[j]=j; euler[j]=euler[j]/i*(i-1); } } int main(){ //freopen("input.txt","r",stdin); getEuler(); for(int i=3;i<=maxn;i++) euler[i]+=euler[i-1]; int n; //printf("%I64d\n",euler[maxn]); while(scanf("%d",&n)!=EOF){ if (!n) break; printf("%I64d\n",euler[n]); } return 0; }
————————————————————————————————————————————————————————————————
看到题的数据量很开心,50*50的矩阵,可以随便搞
看懂题了之后觉得很恶心,怎么处理连通
找到了一个通法:dfs中,由从A格去B格的方向为基础判断
如:A去B的时候,方向为往右走,那么A的开口是必须有右的,B的开口是必须有左的,同理其他三个方向
(说是这么说还是得注意细节,我是用结构体,存储每个节点的开口)
那么这个题就变成了处理联通块个数的问题了(会dfs一定会这种题吧,嗯嗯,一定是)
唯一1A的题,麻烦的题就会尽力注意细节了
int n,m,ans; char mp[maxn][maxn]; int col[maxn][maxn]; int dx[]={0,1,-1,0,0}; int dy[]={0,0,0,1,-1}; struct node{ int u,l,r,d; }Node[maxn][maxn]; void getdir(char ch,node &x){ x.u=x.l=x.r=x.d=0; if (ch=='A') x.u=x.l=1; else if (ch=='B') x.u=x.r=1; else if (ch=='C') x.d=x.l=1; else if (ch=='D') x.d=x.r=1; else if (ch=='E') x.u=x.d=1; else if (ch=='F') x.l=x.r=1; else if (ch=='G') x.u=x.l=x.r=1; else if (ch=='H') x.u=x.d=x.l=1; else if (ch=='I') x.l=x.r=x.d=1; else if (ch=='J') x.r=x.u=x.d=1; else x.u=x.r=x.d=x.l=1; //printf("%d %d %d %d\n",x.u,x.r,x.l,x.d); } bool check(int x,int y,int nx,int ny,int dir){ if (dir==1&&Node[x][y].d&&Node[nx][ny].u) return true; if (dir==2&&Node[x][y].u&&Node[nx][ny].d) return true; if (dir==3&&Node[x][y].r&&Node[nx][ny].l) return true; if (dir==4&&Node[x][y].l&&Node[nx][ny].r) return true; return false; } void dfs(int x,int y){ for(int k=1;k<=4;k++){ int nx=x+dx[k]; int ny=y+dy[k]; if (nx>=1&&nx<=n&&ny>=1&&ny<=m&&!col[nx][ny]) if (check(x,y,nx,ny,k)){ col[nx][ny]=ans; dfs(nx,ny); } } } int main(){ //freopen("input.txt","r",stdin); while(scanf("%d%d",&n,&m)!=EOF){ ans=0; if (n==-1&&m==-1) break; memset(col,0,sizeof(col)); for(int i=1;i<=n;i++) scanf("%s",mp[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) getdir(mp[i][j],Node[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if (!col[i][j]){ ans++; col[i][j]=ans; dfs(i,j); } printf("%d\n",ans); } return 0; }
————————————————————————————————————————————————————————————————
直接让我想退役不想玩了的题
想做模拟的方法竟然不会写了
看完题,关键词any,就是说每次算完两个小的数之和再次排序再次取两个小的,那么:哈夫曼!
直接优先队列搞一发,每次取最小的两个呗
写了个优先队列的基本使用方法以及优先级的定义:
优先队列学习戳我
priority_queue<int,vector<int>,greater<int> > q; int main(){ //freopen("input.txt","r",stdin); int n,num,ans,num1,num2; while(scanf("%d",&n)!=EOF){ ans=0; while(!q.empty()) q.pop(); for(int i=1;i<=n;i++){ scanf("%d",&num); q.push(num); } for(int i=1;i<n;i++){ num1=q.top(); q.pop(); num2=q.top(); q.pop(); num=num1+num2; ans+=num; q.push(num); } printf("%d\n",ans); } return 0; }
————————————————————————————————————————————————————————————————
数学想法题
所谓阶乘,需要去找到特殊的数:质数
要求数位最多,那么尽可能拆分才会最多:分解质因数
但是质数没法拆分:知道了2,3,5,7的处理方法
4,6,8,9怎么办?
尽可能用小的
一定要注意阶乘:9!=7!*8*9=7!*(2*2*2)*(3*3)=7!*3!*3!*2!
那么每个数字单独搞就好
细节:(wa了几发):n的范围:int存不下
直接字符串搞就好了的
int num[20]; int n,x; char s[20]; int main(){ //freopen("input.txt","r",stdin); while(scanf("%d",&n)!=EOF){ scanf("%s",&s); memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ x=s[i]-'0'; if (x==2) num[2]++; else if (x==3) num[3]++; else if (x==4) num[3]++,num[2]+=2; else if (x==5) num[5]++; else if (x==6) num[5]++,num[3]++; else if (x==7) num[7]++; else if (x==8) num[7]++,num[2]+=3; else if (x==9) num[7]++,num[2]++,num[3]+=2; } for(x=7;x>=2;x--) if (num[x]) while(num[x]){ printf("%d",x); num[x]--; } puts(""); } return 0; }
————————————————————————————————————————————————————————————————
总结:
简单题需要保证好细节的1A
难题需要慢慢找回来节奏去学
不管怎么样,祝周末的蓝桥杯顺利