前言:這場cf我當晚給忘了,事後補的,補了4題,沒有一道題是1a的,很難受,痛定思痛,發現自己的思維存在一些問題,現結合這些問題,總結ac的正確打開方式。
鏈接:http://codeforces.com/contest/1037
A題:
一開始看到tourist大神,一分鐘就a了此題,心想肯定是規律題,於是寫了前幾個之後,就草草,猜了一個規律(貌似是n+C(n,2)),結果wa了,後來就老老實實結合題意進行推導了。
其實給你n個數字,進行組合,那麼可以組合成(C(n,1)+C(n,2)+...+C(n,n)=2^n-1)個不同的數字,對於本題,只要這n個數字是連續的就可以了。
所以公式就是ans = log2(n)+1;
錯誤類型:題目理解正確,所寫即所想,數據類型範圍均合適,程序正常執行(未越界,未除零),代碼速度達已最優,所想卻爲錯。
解決方式:重新想算法。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
inline ll read(){
ll sgn = 1; ll sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
ll n = read();
ll ans = 0;
//一開始直接模擬求解的,其實直接套公式就行
// while (pow(2, ans) < n) {
// ans++;
// }
// if((ll)pow(2, ans) == n)
// ans++;
ans = log2(n)+1;
printf("%lld\n",ans);
return 0;
}
B題:
這題tourist大神是2分鐘a的,強啊,簡直超人類啊。而我這個菜雞思考了一會,發現只要先排個序,取中間的那個,然後把它朝目標s進行加減就行,需要注意的是,當中間的那個數變爲s之後,此時數組可能已經不是從小到大的順序了,爲了讓它保持在中間位置,就需要對它前後的數字進行處理,保證在它前面的都小於等於它(如果此時它之間的數比它大,就得把這個數減到爲s),對它後面的數字進行相似的處理。
實現完代碼就交了,結果wa在第十個。。。。仔細又看了代碼,發現自己的代碼可能數組越界,少了對下標的判斷。
錯誤原因:
題目理解正確,所想也正確,所寫即所想,數據類型範圍均合適,代碼速度達已最優,程序未正常執行(越界或者除零)。
解決方式:謹防下標越界。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 2e5 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
inline int read(){
int sgn = 1; int sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
int arr[maxn];
ll n,s;
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
n = read(); s = read();
fo(i, 0, n)
arr[i] = read();
sort(arr, arr+n);
ll mid = n>>1;
ll ans = 0;
ll ind = 0;
if(arr[mid] == s){
printf("%lld\n",ans);
return 0;
}else if(arr[mid] < s){
ans += s-arr[mid];
ind = mid+1;
while (arr[ind] < s && ind < n) { //要對ind判斷是否越界
ans += s-arr[ind];
ind++;
}
}else if(arr[mid] > s && ind >= 0){ //要對ind判斷是否越界
ans += arr[mid]-s;
ind = mid-1;
while (arr[ind] > s) {
ans += arr[ind]-s;
ind--;
}
}
printf("%lld\n",ans);
return 0;
}
C
這道題也很容易想到解法,第一個操作(交換操作)當且僅當i和j相鄰,纔會執行,否則就執行第二個操作,這是最優策略。
也是很快就寫好代碼了,交了一發,還是wa。。。。難受啊。。。
仔細分析,這個策略絕對是最優策略,不可能出錯,那麼就是代碼問題了。於是又是檢查代碼,發現在判斷執行第一個操作是,判斷條件錯了,我寫的是if(arr1[ind] != arr2[ind] && ind+1 < n && arr1[ind+1] != arr2[ind+1]),這是不對的,當arr1[ind]=arr1[ind+1]時,是不需要交換的,改成if(arr1[ind] != arr2[ind] && ind+1 < n && arr1[ind+1] != arr2[ind+1] && arr1[ind] != arr1[ind+1])就過了。
錯誤原因:
題目理解正確,所想也正確,數據類型範圍均合適,代碼速度達已最優,程序正常執行(未越界,未除零),所寫卻非所想。
解決方式:
仔細讀代碼,尋找隱藏bug。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e6 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
inline int read(){
int sgn = 1; int sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
int n;
char arr1[maxn], arr2[maxn];
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
n = read();
int ans = 0;
fo(i, 0, n)
scanf("%c",&arr1[i]);
getchar();
fo(i, 0, n)
scanf("%c",&arr2[i]);
int ind = 0;
while (ind < n) {
if(arr1[ind] != arr2[ind] && ind+1 < n && arr1[ind+1] != arr2[ind+1] && arr1[ind] != arr1[ind+1]){
ans++;
arr1[ind] = arr2[ind]; arr1[ind+1] = arr2[ind+1];
ind += 2;
}else if(arr1[ind] != arr2[ind]){
ans++;
ind++;
}else{
ind++;
}
}
printf("%d\n",ans);
return 0;
}
D
這題題意很簡單,就是要求你寫一個bfs,然後判斷能否輸出規定的序列。
第一次嘗試cf的D題(我菜啊。。。),這次的D題還是可以寫的,直接用bfs模擬就行,依次遍歷要輸出的序列中的字母,在當前頂點的鄰接點中find,若是找到,就繼續找下一個字母,弱若是找不到,就在隊列中下一個頂點中的鄰接點中find,最後判斷一下,是否完全輸出了規定序列就行。
一開始一直wa在第39個樣例,一直找不到wa點,後來仔細讀題才發現,題目有一行字加粗了。。。要求序列必須從1開始。。。我這是睜眼瞎啊。。。
改了之後,又交了一發,結果發現T在第48個,心想是自己的算法不對嗎,仔細分析了自己的算法,發現並不應該超時啊,仔細看了代碼,發現在查找時,用的是algothrim中的find函數,之前一直以爲庫函數中的函數複雜度都挺好的,那麼這個find函數怎麼說都應該達到O(logn)吧,結果並沒有。。。這個函數的複雜度是O(n)的,心想也對,要達到O(logn),應該要用二分,那麼二分的前提是有序,作爲適用所有結構的“通用find函數",自然不會採用二分,那麼如果用了O(n)的find,超時那是肯定的,所以得用logn的find函數,而這樣的find函數,只能調用map、set容器自帶的find函數,st.find(x)。
錯誤原因:
①題意沒看清,忽略了一些特定的條件
②超時的話,不一定算法就不行,可能是有些部分、有些函數不是很優化。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 2e6 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
inline int read(){
int sgn = 1; int sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
set<int> mp[maxn];
int arr[maxn], vis[maxn];
int n;
int success;
queue<int> que;
void bfs(){
int ind = 1;
int startt = arr[0];
while (!que.empty()) {
que.pop();
}
que.push(startt);
vis[startt] = 1;
while (!que.empty()) {
int front = que.front();
que.pop();
while (1) {
int aim = arr[ind];
if(mp[front].find(aim) == mp[front].end())
break;
if(!vis[aim]){
vis[aim] = 1;
que.push(aim);
ind++;
if(ind == n){
success = 1;
return;
}
}else{
success = 0;
return;
}
}
}
if(ind < n)
success = 0;
else
success = 1;
return ;
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
n = read();
fo(i, 0, n-1){
int u = read(); int v = read();
mp[u].insert(v);
mp[v].insert(u);
}
fo(i, 0, n){
arr[i] = read();
}
if(arr[0] != 1){
printf("No\n");
return 0;
}
fi(vis, maxn-5, 0); success = 0;
bfs();
if(success)
printf("Yes\n");
else
printf("No\n");
return 0;
}
通過上面四題,總結了AC的正確打開方式:
①讀懂題意,不能忽略一些細節要求
②選擇合適的數據類型以及合適的存儲範圍
③選擇合適的算法,如果超時了,也不要全盤否定,可能還可以優化
④做到所寫即所想,如果wa了,查查代碼是否實現了自己所想的功能。查查是否越界啥的,或者”=“與”==“問題,初始化,除零等問題,還是wa的話,就得想想自己的算法是否正確了。
另外可以參看:我寫的debug總結:https://blog.csdn.net/vaeloverforever/article/details/81783932