這場我們隊只過了兩道題,五個小時一直自閉中。
B題思維題,沒想出來
C題數位DP,比賽的時候沒仔細看題,覺得太復雜就沒看
D題分類討論加二分,捋不清楚分哪幾種
G題簽到題
I題讀錯了,wa在了m==1的情況,m==1時,圓心點不計入
L題讀完題就在想一個最優解,結果做法是枚舉有可能是最優的點,線性復雜度
M題簽到題,隊友說有思路,我就直接看別的題去了,結果調了挺久
B題:
題意:
給一個n、m,以及兩個n×m的圖,X代表周圍地雷的個數,.代表地雷。
將第二個圖修改(.變為X或X變為.)至多m*n/2次使得X的值的總和等於第一個圖的X的值的總和
輸出修改后的圖
思路:
X的值的綜合即為每個九宮格中X與.的對數之和
將X變換為.,.變換為X,X的值的總和不變。
故做法為變換不超過m*n/2次數下,修改成圖1的原圖或圖一.與X互換后的圖
代碼:
#include<bits/stdc++.h> using namespace std; char a[1005][1005],b[1005][1005]; int main(){ int n,m; cin>>n>>m; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>a[i][j]; } } int diff=0; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>b[i][j]; if(b[i][j]!=a[i][j]) diff++; } } if(diff>n*m/2){ for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ a[i][j]=(a[i][j]=='X'?'.':'X'); } } } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cout<<a[i][j]; } cout<<endl; } }
D題:
在一個長為n的線段,左端點為0,右端點為n
有兩個端點分別位於p1,p2,它們的速度分別為v1,v2
問最少需要多少時間,可以使得p1,p2的路程覆蓋整條線段
思路:
分類討論:
先令p1<p2
①p1走完全程
②p2走完全程
③p1向右走完全部,p2向左走完全部
④p1走完左邊的全部,p2走完右邊的全部,剩余中間的部分p1與p2共同走完,二分路程或時間即可
代碼:
#include<bits/stdc++.h> using namespace std; const double eps=1e-8; double n,p1,p2,v1,v2; int main(){ int t; cin>>t; while(t--){ cin>>n>>p1>>v1>>p2>>v2; if(p1>p2){swap(p1,p2);swap(v1,v2);}; //p1走完全程 double ans=min(p1+n,2*n-p1)/v1; //p2走完全程 ans=min(ans,min(2*n-p2,p2+n)/v2); //p1走完右邊全程,p2走完左邊全程 ans=min(ans,max((n-p1)/v1,p2/v2)); //p1走完左邊全程,p2走完右邊全程,二分分界點 double l=p1,r=p2; while(r-l>eps){ double mid=(l+r)/2; double ans1=min(p1+mid,2*mid-p1)/v1,ans2=min(2*n-p2-mid,p2+n-2*mid)/v2; ans=min(ans,max(ans1,ans2)); if(ans1<ans2)//p1先走完 分界點向右移 l=mid; else r=mid; } printf("%.10lf\n",ans); } }
G題:
簽到題
題意:
對於斐波那契數列 1、1、2、3、5、8、13、21、34……
給一個n計算所有g(fi,fj)的和(i<j)
對於a和b,當a*b為偶數時g(a,b)=1,否則g(a,b)=0;
思路:
觀察斐波那契數列易得,當i%3==0時fi為偶數
當兩個數都不是奇數時,兩個數乘積為偶數
從數列中選出兩對共有C2(n)種選法
偶數的個數有n/3個 則奇數的個數有n-n/3
故答案為C2(n)-C2(n-n/3)
代碼:
#include<bits/stdc++.h> #define ll long long using namespace std; ll C2(ll a){ return a*(a-1)/2; } int main(){ ll n; cin>>n; ll m=n/3; cout<<C2(n)-C2(n-m)<<endl; }
I題:
給一個n和m。
有n個圓心在(0,0)的圓,第i個圓的半徑為i
有m條經過(0,0)的線將這些圓分為等份
線與線、線與圓會產生交點,求這些交點兩兩之間的最短路徑和
思路:
對於外層圓上的點到內層圓上的點的最短路徑必然要先向圓心走到同層的位置
故可以通過遞推的方式來做
唯一要注意的是m=1時不包括圓心,m>1時包括了圓心
代碼:
#include<bits/stdc++.h> using namespace std; #define ll long long #define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL) const int maxn = 1e6 + 10; const double PI=acos(-1); double a[505],b[505]; int n,m; int main() { fastio; cin>>n>>m; double cnt=0; for(int i=1;i<m;i++){ if(PI*i<2*m) cnt+=PI*i/m; else cnt+=2; //cout<<cnt<<endl; } cnt*=2; cnt+=2; a[1]=cnt;b[1]=a[1]; //cout<<a[1]<<endl; for(int i=2;i<=n;i++){ a[i]=a[i-1]+(i-1)*(2*m)+i*b[1]; b[i]=i*b[1]; } double ans=0; for(int i=1;i<=n;i++){ ans+=2*m*(a[i]-b[i])+m*b[i]; if(m>1) ans+=2*i*m; } printf("%.10lf\n",ans); return 0; }
L題:
題意:
有一個網格圖n×m
左下點為(0,0),右上點為(n,m)
從一個點可以到達任意點,但路徑不能出現其他點(或者說,不能出現兩條路徑是相連接的)
求從(0,0)到(n,m)的最短路徑
思路:
如果gcd(n,m)==1,則從(0,0)到(n,m)上無其他點,最短路徑為√(n2+m2)
否則,路徑分為兩段 從(0,0)到(x,y),從(x,y)到(n,m)
枚舉每個x,對於每個x,y的值在x*m/n附近取值一定是最優的
代碼:
#include<bits/stdc++.h> #define ll long long using namespace std; ll gcd(ll a,ll b){ return a%b?gcd(b,a%b):b; } int main(){ ll t,n,m; cin>>t; while(t--){ cin>>n>>m; double ans; if(gcd(n,m)==1){ ans=sqrt(n*n+m*m); }else{ ans=1e15; for(ll x=1;x<n;x++){ ll y=x*m/n,y1,y2; if(x*m==y*n){y1=y-1,y2=y+1;} else{y1=y,y2=y+1;} if(gcd(y1,x)==1&&gcd(m-y1,n-x)==1){ ans=min(ans,sqrt(x*x+y1*y1)+sqrt((n-x)*(n-x)+(m-y1)*(m-y1))); } if(gcd(y2,x)==1&&gcd(m-y2,n-x)==1){ ans=min(ans,sqrt(x*x+y2*y2)+sqrt((n-x)*(n-x)+(m-y2)*(m-y2))); } } } printf("%.15lf\n",ans); } }
M題: