A.Don't Try to Count
輸入樣例:
12 1 5 a aaaaa 5 5 eforc force 2 5 ab ababa 3 5 aba ababa 4 3 babb bbb 5 1 aaaaa a 4 2 aabb ba 2 8 bk kbkbkbkb 12 2 fjdgmujlcont tf 2 2 aa aa 3 5 abb babba 1 19 m mmmmmmmmmmmmmmmmmmm
輸出樣例:
3 1 2 -1 1 0 1 3 1 0 2 5
思路:簽到題,但要注意當字符串a的長度大于2倍的b長度還沒有子串b時,說明a中不可能出現子串b,要退出循環。?
代碼:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{int t;cin>>t;while(t--){int n,m;cin>>n>>m;string a,b;cin>>a>>b;int cnt=0,f=0;while(a.find(b)==string::npos){a+=a;cnt++;if(a.size()>2*m&&a.find(b)==string::npos){cout<<-1<<endl;f=1;break;}}if(!f)cout<<cnt<<endl;}
}
B. Three Threadlets?
輸入樣例:
15 1 3 2 5 5 5 6 36 12 7 8 7 6 3 3 4 4 12 12 6 8 1000000000 1000000000 1000000000 3 7 1 9 9 1 9 3 6 2 8 2 5 3 10 8 4 8 2 8 4
輸出樣例:
YES YES NO NO YES YES NO YES NO NO YES YES NO YES NO
思路:找規律,通過模擬樣例可以發現三根線要一樣長,那么最終長度肯定是要與最短的那根線一樣長,如果某根線不能剪成最短長度,說明這根線不能被最短的長度整除,直接輸出NO就可以了,如果能被整除,那么比較這兩根線的長度和/最短長度得到的結果是否會大于3,大于就輸出NO,反之YES。
代碼:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{int t;cin>>t;while(t--){vector<int> v(3);int f=0,cnt=0;for(auto &it:v) cin>>it;sort(v.begin(),v.end());f=(v[1]%v[0]||v[2]%v[0]);if(f) puts("NO");else{cnt=v[1]/v[0]-1+(v[2]/v[0]-1);if(cnt<=3) puts("YES");else puts("NO");}}
}
C. Perfect Square
輸入樣例:
5 4 abba bcbb bccb abba 2 ab ba 6 codefo rcesco deforc escode forces codefo 4 baaa abba baba baab 4 bbaa abba aaba abba
輸出樣例:
1 2 181 5 9
思路:?因為題目要求矩陣翻轉90°之后仍保持不變,說明矩陣的每一條邊上的字母都得一樣,所以我們可以通過從上往下的每一行的邊與另外三條邊上對應的元素進行比較(總共只需要遍歷n/2行),因為只能將字母變大,所以我們要找到這四條邊中最大的字母是哪個,然后另外三個字母就變成這個最大字母maxd,變化次數為4*maxd-(a1+a2+a3),然后我們要記得將原位置更小的字母改成更大的字母,具體可看代碼。
代碼:
#include<iostream>
using namespace std;
const int N=1e3+5;
char a[N][N];
int main()
{int t;cin>>t;while(t--){int n,sum=0;cin>>n;for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];for(int i=1;i<=n/2;i++)for(int j=1+i-1;j<=n-i;j++){int a1=a[i][j]-'a'; //cout<<a1<<' ';int a2=a[n-j+1][i]-'a'; //cout<<a2<<' ';int a3=a[n-i+1][n-j+1]-'a';// cout<<a3<<' ';int a4=a[j][n-i+1]-'a'; //cout<<a4<<' ';int maxd=max(a1,max(a2,a3));maxd=max(maxd,a4);sum+=4*maxd-(a1+a2+a3+a4);if(a1!=maxd)a[i][j]+=maxd-a1;if(a2!=maxd)a[n-j+1][i]+=maxd-a2;if(a3!=maxd)a[n-i+1][n-j+1]+=maxd-a3;if(a4!=maxd)a[j][n-i+1]+=maxd-a4;// cout<<maxd<<' '<<sum<<' '<<a1+a2+a3+a4<<endl;// cout<<maxd<<' '<<a[4][2]<<endl;//puts("");}cout<<sum<<endl;}
}
D. Divide and Equalize
輸入樣例:
7 5 100 2 50 10 1 3 1 1 1 4 8 2 4 2 4 30 50 27 20 2 75 40 2 4 4 3 2 3 1
輸出樣例:
YES YES NO YES NO YES NO
思路:?這道題一開始沒什么思路,后面看了一些大佬的題解才恍然大悟(heheh( ̄▽ ̄)"終歸還是我太菜了),首先我們要知道每個大于1的數都可以分解成幾個質因數的乘積,那么這道題的操作是一個數除k的同時另一個數乘k,因數的個數是不會變的,我們可以將其看成因數的轉移,所以這n個數中每個質因數的個數如果為n的整數倍則可以將他們變成一樣的數,否則不能。
代碼:
#include<iostream>
#include<map>
using namespace std;int main()
{ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);int t;cin>>t;while(t--){int n;cin>>n;map<int,int> h;for(int i=0;i<n;i++){int x;cin>>x;for(int m=2;m<=x/m;m++){while(x%m==0){h[m]++;x/=m;}}if(x>1) h[x]++;}int f=0;for(auto it:h){if(it.second%n!=0){f=1;break;}}if(f) puts("NO");else puts("YES");}
}
E. Block Sequence
輸入樣例:
7 7 3 3 4 5 2 6 1 4 5 6 3 2 6 3 4 1 6 7 7 3 1 4 3 5 1 2 3 4 5 5 1 2 3 1 2 5 4 5 5 1 5
輸出樣例:
0 4 1 1 2 1 0
思路:?這道題我們要從后往前dp,定義dp[i]為從n到i的最少操作次數,由題意可知我們對一個數字有兩種操作,刪除:dp[i]=dp[i+1]+1,保留 :dp[i]=dp[i+a[i]+1],我們只需要在這兩種操作中取最小值就可以了。
代碼:
#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+5;
int a[N],dp[N];
/*逆向dp*/
int main()
{ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);int t;cin>>t;while(t--){int n;cin>>n;memset(dp,0,sizeof dp);for(int i=1;i<=n;i++) cin>>a[i];for(int i=n;i>=1;i--){dp[i]=dp[i+1]+1;//刪除if(i+a[i]<=n) dp[i]=min(dp[i],dp[i+a[i]+1]);//比較保留和刪除兩種操作}cout<<dp[1]<<endl;}
}
F. Minimum Maximum Distance
輸入樣例1:
6 7 3 2 6 7 1 2 1 3 2 4 2 5 3 6 3 7 4 4 1 2 3 4 1 2 2 3 3 4 5 1 1 1 2 1 3 1 4 1 5 5 2 4 5 1 2 2 3 1 4 4 5 10 8 1 2 3 4 5 8 9 10 2 10 10 5 5 3 3 1 1 7 7 4 4 9 8 9 6 1 10 9 1 2 4 5 6 7 8 9 10 1 3 3 9 9 4 4 10 10 6 6 7 7 2 2 5 5 8
輸出樣例1:
2 2 0 1 4 5
輸入樣例2:
3 6 1 3 1 2 1 3 3 4 3 5 2 6 5 3 1 2 5 1 2 1 3 2 4 3 5 7 1 2 3 2 2 6 6 1 5 6 7 6 4 5
輸出樣例2:
0 2 0
思路:?fi的最小值只會出現在兩個或多個標記頂點中間的點到標記頂點的最大距離,找兩個標記頂點的最大距離相當于找樹的直徑(傳送門),結果輸出(樹的直徑-1)/2+1。
代碼:
/*樹的直徑————兩次dfs第一次dfs算出所有結點到根節點的距離,到根節點最大距離的那個結點就是樹的直徑的一個端點第二次dfs以端點為根節點,算出其他點到直徑端點的距離,然后取距離最大的那個點即為直徑的另一個端點第二次dfs求到的到端點的最大距離即為樹的直徑*/#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N=2e5+5;
int depth[N],mark[N];
vector<int> edge[N];
void dfs(int u,int fa)
{for(auto t:edge[u]){if(t==fa) continue;depth[t]=depth[u]+1;dfs(t,u);}
}
int main()
{ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);int t;cin>>t;while(t--){int n,k;cin>>n>>k; for(int i=1;i<=n;i++) edge[i].clear();//vector<int> edge[n];for(int i=1;i<=k;i++) cin>>mark[i];for(int i=1;i<n;i++) {int a,b;cin>>a>>b;edge[a].emplace_back(b),edge[b].emplace_back(a);}depth[1]=0;if(k==1){cout<<0<<endl;continue;}dfs(1,-1);int c=mark[1];for(int i=2;i<=k;i++) if(depth[mark[i]]>depth[c]) c=mark[i];//先求直徑的一個端點depth[c]=0;dfs(c,-1);//從這個被標記的端點出發找另一個端點c=mark[1];for(int i=2;i<=k;i++)if(depth[mark[i]]>depth[c]) c=mark[i];cout<<(depth[c]-1)/2+1<<endl;}
}
(將近半個月沒寫cf了,A題都讓我TLE了一發,暑假得刷起來了😂,話說學校暑假放得真晚,還在復習期末考試科目( ̄▽ ̄)"。。。