NOIP2009 题解
题解:
简单的字符串模拟,是一道签到题。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; char s1[maxn]; char s2[maxn]; char p[maxn]; int mp[maxn]; int mp1[maxn]; int main(){ scanf("%s",s1+1); scanf("%s",s2+1); scanf("%s",p+1); int len=strlen(s1+1); int len2=strlen(p+1); for(int i=1;i<=len;i++){ if(!mp[s1[i]-'A'+1]) mp[s1[i]-'A'+1]=s2[i]-'A'+1; else{ if(mp[s1[i]-'A'+1]!=s2[i]-'A'+1){ printf("Failed\n"); return 0; } } if(!mp1[s2[i]-'A'+1]) mp1[s2[i]-'A'+1]=s1[i]-'A'+1; else{ if(mp1[s2[i]-'A'+1]!=s1[i]-'A'+1){ printf("Failed\n"); return 0; } } } for(int i=1;i<=26;i++){ if(!mp[i]){ printf("Failed\n"); return 0; } } for(int i=1;i<=len2;i++) printf("%c",mp[p[i]-'A'+1]+'A'-1); printf("\n"); return 0; }
题解:
50分暴力有手就能写,但是我们肯定要想正解。
100分正解:还是不太容易想到,参考了一本通上的做法。
#include<bits/stdc++.h> #define int long long using namespace std; int tot; int n; int a0,a1,b0,b1; int gcd(int a,int b){ if(!b) return a; return gcd(b,a%b); } int lcm(int a,int b){ return a*b/gcd(a,b); } signed main(){ cin>>n; for(int i=1;i<=n;i++){ tot=0; scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1); if(b1%b0){ printf("0\n"); continue; } int x; for(int j=1;j<sqrt(b0);j++){ if(b0%j==0){ x=(b1/b0)*j; if(gcd(x,b0)==j&&gcd(x,a0)==a1) tot++; x=(b1/b0)*(b0/j); if(gcd(x,b0)==b0/j&&gcd(x,a0)==a1) tot++; } } int k=(int)sqrt(b0); if(k*k==b0&&b0%k==0){ x=(b1/b0)*k; if(gcd(x,b0)==k&&gcd(x,a0)==a1) tot++; } printf("%lld\n",tot); } return 0; }
题解:
暑假讲过这道题,思想非常常见,有向图建反边,然后更新最大值最小值即可。
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; const int INF=0x3f3f3f3f; struct node{ int nxt; int to; }edge[maxn*2]; struct node1{ int nxt; int to; }edge1[maxn*2]; int x,y,z; int n,m; int head[maxn],cnt; int val[maxn]; int mi[maxn],mx[maxn]; bool vis[maxn]; void add(int x,int y){ edge[++cnt].nxt=head[x]; edge[cnt].to=y; head[x]=cnt; } int head2[maxn],cnt2; void add2(int x,int y){ edge1[++cnt2].nxt=head2[x]; edge1[cnt2].to=y; head2[x]=cnt2; } queue<int> q; void spfa1(){ for(int i=1;i<=n;i++){ mi[i]=INF; vis[i]=false; } mi[1]=val[1]; q.push(1); vis[1]=true; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(mi[v]>min(mi[u],val[v])){ mi[v]=min(mi[u],val[v]); if(!vis[v]){ q.push(v); vis[v]=true; } } } } } void spfa2(){ for(int i=1;i<=n;i++){ mx[i]=-INF; vis[i]=false; } mx[n]=val[n]; q.push(n); vis[n]=true; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head2[u];i;i=edge1[i].nxt){ int v=edge1[i].to; if(mx[v]<max(mx[u],val[v])){ mx[v]=max(mx[u],val[v]); if(!vis[v]){ q.push(v); vis[v]=true; } } } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&val[i]); } for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); if(z==1){ add(x,y); add2(y,x); } else{ add(x,y); add(y,x); add2(x,y); add2(y,x); } } spfa1(); spfa2(); int ans=0; for(int i=1;i<=n;i++){ ans=max(ans,mx[i]-mi[i]); } printf("%d\n",ans); return 0; }
题解:
一开始我写的是50分的填数独,非常naive。
这题是一道搜索好题。网上常有的方法是二进制判断,但我只会稍微剪枝而已。
对于此题已经足够了,换一种搜索方式,枚举剩下多少格子没有填。然后每次可以枚举一下判断下次该填那个格子。有一个贪心的思路就是每次枚举可填的数最少的格子。这样能有效减少状态分枝。
#include<bits/stdc++.h> using namespace std; int sudoku[150][150]; int score[10][10]{ {0,0,0,0,0,0,0,0,0,0}, {0,6,6,6,6,6,6,6,6,6}, {0,6,7,7,7,7,7,7,7,6}, {0,6,7,8,8,8,8,8,7,6}, {0,6,7,8,9,9,9,8,7,6}, {0,6,7,8,9,10,9,8,7,6}, {0,6,7,8,9,9,9,8,7,6}, {0,6,7,8,8,8,8,8,7,6}, {0,6,7,7,7,7,7,7,7,6}, {0,6,6,6,6,6,6,6,6,6}, }; int line[150][150]; int row[150][150]; int area[150][150]; long long maxx; long long sum; int tot; void dfs(int rest,long long all){ if(!rest){ maxx=max(maxx,all); return; } int sss=19260817,xx,yy,step; for(int i=1;i<=9;i++){ for(int j=1;j<=9;j++){ if(!sudoku[i][j]){ step=0; for(int k=1;k<=9;k++){ if(!line[j][k]&&!row[i][k]&&!area[(i-1)/3*3+(j-1)/3+1][k]) step++; } if(step<sss){ sss=step; xx=i; yy=j; } } } } for(int i=1;i<=9;i++){ if(!line[yy][i]&&!row[xx][i]&&!area[(xx-1)/3*3+(yy-1)/3+1][i]&&!sudoku[xx][yy]){ line[yy][i]=true; row[xx][i]=true; area[(xx-1)/3*3+(yy-1)/3+1][i]=true; sudoku[xx][yy]=i; all+=sudoku[xx][yy]*score[xx][yy]; dfs(rest-1,all); line[yy][i]=false; row[xx][i]=false; area[(xx-1)/3*3+(yy-1)/3+1][i]=false; all-=sudoku[xx][yy]*score[xx][yy]; sudoku[xx][yy]=0; } } } int main(){ maxx=-1; for(int i=1;i<=9;i++){ for(int j=1;j<=9;j++){ scanf("%d",&sudoku[i][j]); if(sudoku[i][j]){ tot++; line[j][sudoku[i][j]]=true; row[i][sudoku[i][j]]=true; area[(i-1)/3*3+(j-1)/3+1][sudoku[i][j]]=true; sum+=score[i][j]*sudoku[i][j]; } } } dfs(81-tot,sum);//还有多少空格 printf("%d\n",maxx); return 0; }