前言:这场又蹦了。。。还是老老实实补题吧。
A:水题就不说了
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
using namespace std;
string s[1010];
int main(){
int n;
while(cin>>n){
int ans=0;
rep(i,0,n){
cin>>s[i];
if(!ans){
if(s[i][0]=='O'&&s[i][1]=='O'){
s[i][0]='+';s[i][1]='+';
ans=1;
}
else if(s[i][3]=='O'&&s[i][4]=='O'){
s[i][3]='+';s[i][4]='+';
ans=1;
}
}
}
if(!ans) cout<<"NO"<<endl;
else{
cout<<"YES"<<endl;
rep(i,0,n) cout<<s[i]<<endl;
}
}
}
B:
题意:n*n矩阵 里,有一个位置是0,待你填入一个大于0的数,使得矩阵每行,每列,两对角线之和相等,输出可能存在的这个数,不存在输出-1.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[800][800];
int n;
bool check(int x,int y,ll v){
a[x][y]=v;
ll ans=0,sum=0;
for(int i=1;i<=n;i++) ans+=a[1][i];
for(int i=1;i<=n;i++){
sum=0;
for(int j=1;j<=n;j++) sum+=a[i][j];
if(sum!=ans) return false;
}
for(int i=1;i<=n;i++){
sum=0;
for(int j=1;j<=n;j++) sum+=a[j][i];
if(sum!=ans) return false;
}
sum=0;
for(int i=1;i<=n;i++) sum+=a[i][i];
if(sum!=ans) return false;
sum=0;
for(int i=1;i<=n;i++) sum+=a[i][n+1-i];
if(sum!=ans) return false;
return true;
}
int main(){
while(~scanf("%d",&n)){
int x,y;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]==0) {x=i;y=j;}
}
}
if(n==1){
cout<<10<<endl;
continue;
}
ll sum=0,ans=0;
int p=1;
while(x==p) p++;
for(int i=1;i<=n;i++){
sum+=a[x][i];
ans+=a[p][i];
}
if(check(x,y,ans-sum)&&ans-sum>0) cout<<ans-sum<<endl;
else cout<<-1<<endl;
}
}
C:
题意:有n个数的序列,多少个不相同的连续序列的个数是他的美丽度。比如 :1 2 2 1 美丽度是3 ,{1} {2,2} {1}三个不相同的连续序列。
同时每个位置可能预先被选定一个颜色,0表示没有选定。同时给出每个位置用哪个颜色(数字)代价是不同的,问整个串美丽度为k的最消耗费是?
思路:典型区间dp问题。设dp[i][j][k]表示:选到第i个数,美丽度为j的情况下选择k的颜色的最小耗费。
我的做法O(n^4) n<=100
那么详细的转移方程见代码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x7fffffffffff;
ll dp[110][110][110],cost[110][110],c[110];
int main(){
int N,M,K;
while(~scanf("%d%d%d",&N,&M,&K)){
for(int i=1;i<=N;i++) scanf("%I64d",&c[i]);
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
scanf("%I64d",&cost[i][j]);
}
}
for(int i=0;i<=N;i++){
for(int j=0;j<=K;j++){
for(int k=0;k<=M;k++){
dp[i][j][k]=inf;
}
}
}
if(c[1]==0){
for(int i=1;i<=M;i++) dp[1][1][i]=cost[1][i];
}
else{
dp[1][1][c[1]]=0;
}
for(int i=2;i<=N;i++){
for(int j=1;j<=K;j++){
if(c[i]==0){
for(int k=1;k<=M;k++){
for(int l=1;l<=M;l++){
if(k!=l) dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-1][l]+cost[i][k]);
else dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]+cost[i][k]);
}
}
}
else{
for(int k=1;k<=M;k++){
if(k!=c[i]) dp[i][j][c[i]]=min(dp[i][j][c[i]],dp[i-1][j-1][k]);
else dp[i][j][c[i]]=min(dp[i][j][c[i]],dp[i-1][j][c[i]]);
}
}
}
}
ll ans=inf;
for(int i=1;i<=M;i++) ans=min(ans,dp[N][K][i]);
if(ans>=inf) printf("-1\n");
else printf("%I64d\n",ans);
}
}
D:
题意:
给出一个n个节点n条边的有向图,可以把一条边反向,现在问有多少种方式可以使这个图没有自循环的环;
思路:可以发现一共n个边,对于一个环来说,随便反转哪些边就可以,不过有两种不行就是都不反转和都反转,假设这个环有s条边,那么就有2^s-2种方式,其他不在环里的边sum可以反转可以不反转;
所以答案:(2^s-2)*2^sum
具体找每个环内有多少边,和总工有多少边在 环里,一个dfs就好。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2*100000+10;
const ll mod=1e9+7;
int a[N],vis[N],dep[N],sum=0;
ll ans;
ll pow_mod(ll a,ll n){
ll as=1;
ll tmp=a%mod;
while(n){
if(n&1) as=(as*tmp)%mod;
tmp=tmp*tmp%mod;
n>>=1;
}
return as;
}
int dfs(int cur,int deep,int fa){
vis[cur]=fa;
dep[cur]=deep;
if(!vis[a[cur]]) dfs(a[cur],deep+1,fa);
else if(vis[a[cur]]==fa){
ans=ans*(pow_mod(2,dep[cur]-dep[a[cur]]+1)-2+mod)%mod;
sum+=dep[cur]-dep[a[cur]]+1;
}
}
int main(){
int n;
while(~scanf("%d",&n)){
ans=1;sum=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0,i);
ans=ans*pow_mod(2,n-sum)%mod;
printf("%I64d\n",ans);
}
}