前言
這篇題解大概是我 寫的,當時感覺自己 了。 這篇題解已經出爐了,檢查了一下代碼沒發現啥問題,最後一題不會對拍,自閉了,如何生成一棵樹啊。。。
正文
T1
題目描述
小x有一個整數,他想將該數各個位上數字反轉得到一個新數。新數也應滿足整數的常見形式,即除非給定的原數爲零,否則反轉後得到的新數的最高位數字不應爲零。他覺得這個問題太簡單,就將其拋給了你。
題目分析
開始的時候就開始開 ,直接寫完交了
模擬一下就好了
題目代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
int main(){
int n,ans=0;read(n);
if(n<0){putchar('-');n*=-1;}
while(n){
ans=ans*10+n%10;
n/=10;
}cout<<ans;
return 0;
}
T2
題目描述
小x學了編程,但他吃了飯沒事幹,於是想自己寫一個計算器,計算器上有“+”、“-”、“*”、“/”(整除號)的按鍵,但他寫完以後發現他寫錯了,看着幾百行的程序,他心態崩了,不想調,於是讓你給他寫一個計算器,來處理一堆正整數的加減乘除運算。
題目分析
是個模擬題,思路大家應該都清楚,先把數字和符號隔離出來,然後先把乘法和除法算好,次數式子就變成了只有加法和減法的式子,這個沒有難度吧。
題目代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
vector<pair<int,char> >q;
vector<pair<int,char> >s;
int work1(){
for(unsigned i=0;i<q.size();i++){
switch(q[i].second){
case '+':s.push_back(q[i]);break;
case '-':s.push_back(q[i]);break;
case '*':s[s.size()-1].first*=q[i].first;break;//算乘
case '/':s[s.size()-1].first/=q[i].first;break;//算除
}
}
int ans=0;
for(unsigned i=0;i<s.size();i++){
if(s[i].second=='+')ans+=s[i].first;
else ans-=s[i].first;
}return ans;
}
int work(){
string st;
cin>>st;
q.push_back(make_pair(0,'+'));//第1個數前面的符合可以看成是+號
for(unsigned i=0;i<st.size();i++)
if(isdigit(st[i]))q[q.size()-1].first=q[q.size()-1].first*10+st[i]-48;
else q.push_back(make_pair(0,st[i]));
cout<<work1()<<endl;
return 0;
}
int main(){
int T;
read(T);
while(T--){
q.clear();s.clear();
work();
}
return 0;
}
T3
題目描述
小x有一張由n行和m列組成的圖片。行從上到下從1到n編號,列從左到右從1到m編號。每個單元都塗成黑色或白色。
小x認爲這幅畫不夠有趣。如果一幅畫裏至少有一個十字架,你會覺得它很有趣。十字由一對數字x和y表示,其中1≤x≤n和1≤y≤m,這樣x行中的所有單元格和y列中的所有單元格都塗成黑色。
例如,這些圖片中的每個都包含十字架:以下圖像不包含十字架:
你有一把刷子和一罐黑漆,所以你可以使這幅畫有趣。每分鐘你都可以選擇一個白色的單元格,然後把它塗成黑色。問題是你最少需要多少次,才能使圖片至少包含一個十字?
題目分析
先枚舉行,算行需要多少次塗鴉牆,然後看列。
注意一個小細節,行和列有重合的地方。
題目代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
char ch[1010][1010];
int s[1010];
int work(){
int n,m,ans=INT_MAX;read(n);read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>ch[i][j];
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
if(ch[i][j]=='.')s[j]++;
for(int i=1;i<=n;i++){
int sm=0,mx=INT_MAX;
for(int j=1;j<=m;j++)
if(ch[i][j]=='.')sm++;
for(int j=1;j<=m;j++)
mx=min(mx,s[j]-(ch[i][j]=='.'));//這裏!
ans=min(ans,mx+sm);
}cout<<ans<<endl;
return 0;
}
int main(){
int T;read(T);
while(T--){
memset(s,0,sizeof(s));
work();
}
return 0;
}
T4
題目描述
小x自娛自樂,他在黑板上寫下了一行共n個數字,分別是1,2k,22k…2(n-1)k。現在,他想先擦去黑板上第1個數字,然後擦去黑板上剩餘數字中的第2個數字,再擦去剩餘數字中第3個數字……直到小x無法繼續擦去。現在你想知道,算法停止後第x個剩餘數的值是多少。
題目分析
首先,這個擦數會令我們感到不爽,於是,我們看看會取哪些數字。
假設有 個數:
- 擦 ,序列變成
- 擦 ,序列變成
- 擦 ,序列變成
- 擦 ,序列變成
- 擦 ,序列變成
- 無法繼續進行,操作結束
此時很明顯的規律如下:所有的奇數會被擦掉,所有的偶數會被留下。
再拓展一下,最後剩下的數的個數 偶數的個數
這樣的話就簡單了。
首先判斷 ,直接看 是否 。
然後第 個數,顯然等於 。
題目代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int mod=19260817;
ll pw(ll x,ll y){
ll ans=1;
while(y){
if(y&1)ans=ans*x%mod;
y>>=1;
x=x*x%mod;
}return ans;
}
int work(){
ll n,x,k;read(n);read(x);read(k);
n/=2;
if(x>n)return puts("-1"),0;
write(pw(2,(x*2ll-1ll)*k));
puts("");
return 0;
}
int main(){
int T;read(T);
while(T--){work();}
return 0;
}
T5
題目描述
小x管理着N 個城市,這些城市之間有N-1條道路將他們連接起來,小x發現任何兩個城市都能夠直接或者間接通過道路連接。
雖然所有城市是可以互相到達的,但是他擔心有恐怖分子破壞這片區域的安定,破壞道路,於是小x又祕密地修建了 M 條小路來連接。
果不其然,最近一個奇怪的組織意欲破壞道路,請你幫小x想想辦法,如果城市 A 到城市 B 的直連道路被破壞,從 A 走到 B 的所有路徑中,經過小路的距離最少是多少?
題目分析
個點, 條邊,整張圖連通,這不是樹嗎?
首先,樹有一個性質——砍掉任意的一條邊,就不聯通。
我們以一張圖爲例。
- 橙色的邊表示刪除的邊。
- 紅色的邊表示樹上的邊。
- 紫色的邊表示新加的邊。
先說一個結論,如果有解的話,新加的邊用且僅用一次。
爲什麼?
首先一條邊被刪除後,一棵樹變成了兩棵樹,起點和終點必定在不同的樹裏,所以我們需要一座橋連接兩棵樹。
那爲什麼不會使用多條新加的邊呢?因爲在一棵樹內,任意兩點均能相互達到。
知道這個就好辦了。
我們先 找連通塊,遍歷其中一棵子樹。
我們再去找這棵子樹連向另外一棵子樹的新加邊,並從中找到邊權最小的作爲我們的答案。
題目代碼
#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
const int MAXN=1e4+10;
int n,m,x[MAXN],y[MAXN],h[MAXN];
vector<int>v[MAXN];
vector<pair<int,int> >e[MAXN];
vector<int>v1;
void dfs(int x,int fa,int z){
v1.push_back(x);h[x]=1;
for(auto i:v[x])
if(i!=fa&&i!=z)dfs(i,x,z);
}
int main(){
read(n);read(m);
for(int i=1;i<n;i++){
read(x[i]),read(y[i]);
v[x[i]].push_back(y[i]);
v[y[i]].push_back(x[i]);
}
for(int i=1;i<=m;i++){
int x,y,z;read(x);read(y);read(z);
e[x].push_back(make_pair(y,z));
e[y].push_back(make_pair(x,z));
}
for(int i=1;i<n;i++){
v1.clear();memset(h,0,sizeof(h));
dfs(x[i],0,y[i]);
int ans=INT_MAX;
for(auto j:v1)
for(auto k:e[j])
if(!h[k.first])ans=min(ans,k.second);
if(ans==INT_MAX)puts("-1");
else cout<<ans<<endl;
}
return 0;
}
時間複雜度
這個代碼剛寫完時,我嚇了一跳,這不是 嗎?
過了一會兒,我想了想,發現這其實是 的,而且跑不滿。
爲什麼?
我們看 行代碼,這裏並不是 的,而是 的,因爲新加的一條邊最多被訪問 次( 個端點各訪問一次),時間複雜度是忽略常數的,並且這裏是真的跑不滿。
但願這題不 (要 也只會因爲那個 可能 ),不 (沒道理 ),不 (沒資格 ),不 (沒可能 ),不 ( 幫我定着呢),不 (這個網站開 c++11
,我試過)。(所以不可能不 !但願吧。。。)
後記
由於這篇題解是比賽的時候寫的,所以分數暫時還不知道,但願能做對的都做對,最好能 。