CF 1307 A-D
A Cow and Haybles 題目鏈接
題目描述
有n個數, 每次可以選相鄰的兩個數i, j: 使得ai+1, aj-1, 問經過這樣d次操作後, a1最大是多少。
題目思路
首先明白題意, 是任意的兩個數+1, -1, 而且又要使得a1最大, 所以, 我們可以在這d次時間內, 儘量讓a1 每次都加1, 那麼相鄰的a2-1, 那麼如果a2 等於0了呢, 那就讓a3-1, 再讓a2+1, 再讓a1+1, a2-1, 所以, 我們發現, 從a2移到a1需要1步, a3移到a1需要2步, ai移到a1需要i-1步, OK , GET到點了!!!
注意, 不能一下子把一個數全移過去, 只能一個一個移, 因爲你有可能在移的過程中就超過d次了。。。。
代碼
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<cctype>
using namespace std;
int t;
int n, d;
int a[110];
int main()
{
cin >> t;
while(t--)
{
cin >> n >> d;
int now = 2;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
while(d > 0 && now <= n)
{
if(!a[now])
{
now++;
continue;
}
a[now]--;
d = d - (now - 1);
if(d < 0)
{
break;
}
a[1]++;
}
cout << a[1] << endl;
}
return 0;
}
B Cow and Friend 題目網址
題目描述
貝茜有太多朋友了。因爲她是所有人最喜歡的牛。她的朋友兔兔在試着跳到貝茜所在的地方,那麼他們就可以玩了。
更具體地,兔兔他想跳幾步使得他能從(0,0)跳到 (x,0)。他只想着在二維平面上從一個點跳到另一個點當且僅當兩個點的歐幾里得距離是他n個喜歡的數中的其中一個,也就是.
兔兔最少要跳幾步才能從(0,0)跳到(x, 0)呢?兔兔不必跳到一個整數的座標,換句話說,他可以跳到一個不是整數的座標。可以證明,兔兔總可以到達他的終點。
重新在此聲明,兩個點的歐幾里得距離可以使用公式算出,設兩個點的座標分別爲 (x1,y1), (x2, y2), 那麼有公式
如下圖所示,如果兔兔喜歡的數是1和3的話,那麼他可以跳兩步從(0,0)
跳到(4,0)。
圖中的就是樣例的第一個測試的示意圖,兩次跳的距離都是3 ———一個兔兔喜歡的數。換句話說,每一次兔兔都會選一個數 ai然後任意地跳到一個與這個點距離爲ai的地方, 相同的數可以使用多次。
題目思路
貪心
首先明白一件事情, 他讓走最少的步數, 那麼肯定是用最大的距離去走, 所以, 答案爲ceil(x / maxn)
真的那麼簡單嘛??
看下面幾種情況:
1) x % i == 0;
那麼答案就是x / ai, 加入比較行列。
2) 最大步長大於x, 那麼, 答案一定是二, 如圖:
以起點爲圓心作⚪, 與終點爲圓心做⚪, 都已最大步長爲半徑爲交點,就是跳到的間接點, 顯而易見, 跳兩步就能到終點。
到這兒, 應該就講完了, 但我想再稍微的拓展一下, 如果最大步長小於x的話,可見按上面的那種做法兩圓根本交不到。 我們可以讓起點向x軸上先跳到(最大步長, 0)這個點在作⚪, 如果還交不到, 那麼就在往右跳。直到能交到爲止。
代碼
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<cctype>
using namespace std;
int t;
int n;
int x;
int a[100010];
int main()
{
cin >> t;
while(t--)
{
int maxn = -0x3f3f3f3f;
int ans = 0x3f3f3f3f;
bool flag = 0;
memset(a, 0.0, sizeof(a));
cin >> n >> x;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
maxn = max(maxn, a[i]);
if(x == a[i])
{
cout << 1 << endl;
flag = 1;
}
if(a[i] % x == 0)
{
ans = min(ans, a[i] / x);
}
}
if(flag == 1)
{
continue;
}
if(x < maxn)
{
ans = min(ans, 2);
}
else
{
int p = ceil((x+0.0) / maxn);
ans = min(ans, p);
}
cout << ans << endl;
}
return 0;
}
C Cow and message. 題目網址
題目描述
貝茜剛剛截取了來自約翰發送出去的訊息!但是,貝茜很肯定裏面一定有隱藏的訊息。
訊息是一個字符串, 全部都是由小寫拉丁字母字符構成。她認爲一個字符串是隱藏的當且僅當是的子序列, 且在下標中構成了一個等差數列, 公差必須爲一個正整數
。例如,字符串aab是隱藏在字符串aaabb因爲aab出現在的下標是1,3,5.
這剛好構成了一個等差數列,而公差是 2.貝茜覺得祕密訊息訊息一定是隱藏最多次的那一個字符串兩個 中的子序列是不同的當且僅當兩個字符串在中出現的下標是不同的。 請幫貝茜找出祕密訊息在中出現的次數吧。
題目思路
首先明白:祕密信息一定是有一個或兩個。
證明, 首先要知道子字符串在這裏指的是什麼
顯而易見, 我們可以看到, 這個字串裏的字符位置一定是形成公差數列的。
再來考慮三個字符串的情況。
假如abc, 你會發現:當確定ab的所有情況時, c已經確定了, 因爲有公差。比如a和b的公差時3, 那麼這種情況在ab這個字符串裏面就已經包含了, 然而在abc三個字符串裏面你還要判斷在b後面三個位置的字母是否是c, 如果是纔算到字符串abc裏, 所以就得出了這樣一個結論:
三個字母的出現了,兩個字母也出現了,兩個字母出現了,三個字母不一定出現。
多的以此類推。
一個和兩個字串就不同。
因爲在兩個子串裏的時候,假如你要選第二個字母。你會發現公差還沒有確定, 所以設要找的字串爲a,b,那麼a就可能和後面任意一個b去組合。
這就是和三個的區別, 因爲你在找第三個的時候,前面兩個已經確定了公差, 所以你不能和後面的c隨意組合了。。。
說了這麼多, 總之, 只要取一個和兩個字符串裏面出現次數的最大值就可以了吧。。。
用sufij表示維護一個後綴:從i位置到第n個位置有多少個字母j。
那麼一個字母a的出現次數就爲suf【1】【a】;
設ans【i】【j】表示字串爲ij時出現個數。
代碼
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<cctype>
using namespace std;
string s;
int suf[100010][30];
int ans[30][30];
int main()
{
cin >> s;
int len = s.size() - 1;
for(int i = len; i >= 0; i--)
{
suf[i][s[i] - 'a']++;
for(int j = 0; j < 26; j++)
{
suf[i][j] += suf[i+1][j];
}
}
for(int i = 0; i <= len; i++)
{
for(int j = 0; j < 26; j++)
{
ans[s[i] - 'a'][j] += suf[i+1][j];
}
}
int res = 0;
for(int i = 0; i < 26; i++)
{
for(int j = 0; j < 26; j++)
{
res = max(ans[i][j], res);
}
res = max(res, suf[0][i]);
}
cout << res << endl;
return 0;
}
我是不會告訴你們我沒A的 逃)
D Cow and Fields 題目網址
題目描述
給定一個有個節點條邊的有向圖,一個頂點集.
你需要選擇兩個頂點並連接這兩個頂點(允許
之間已經有連邊),求連接後從頂點1到頂點最短路的最大值.
注意:該操作只能進行一次
保證給定的圖聯通。
題目思路
設答案兩個要添邊的點爲i,j。則最短路經過他倆, 那麼最短路的長有兩種
首先設他倆到點1, n的距離分別爲dis1x, dis1y, dis2x, dis2y。
則答案爲
可見是個貪心, 那麼化簡:
設前面的小於後面的
最終得:
就按這個貪;在維護第i到n個點dis2的最大值。
這題我也沒過, 但還是要堅強的貼代碼::
代碼
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<cctype>
using namespace std;
int n, m, k;
int a[200010];
struct edge
{
int y;
int next;
}ed[200010];
int en = 0;
int head[200010];
void add_edge(int x, int y)
{
en++;
ed[en].y = y;
ed[en].next = head[x];
head[x] = en;
}
int dis[200010];
bool vis[200010];
struct point
{
int id;
int d;
point(){}
point(int a, int b)
{
id = a;
d = b;
}
bool operator<(const point &x) const
{
return d > x.d;
}
};
priority_queue<point> pq;
void Dijkstra(int s)
{
memset(dis, 0x3f, sizeof(dis));
memset(vis, false, sizeof(vis));
dis[s] = 0;
pq.push(point(s, 0));
while(!pq.empty())
{
point now = pq.top();
pq.pop();
if(vis[now.id])
{
continue;
}
vis[now.id] = 1;
//cout << now.id << " ";
for(int p = head[now.id]; p != 0; p = ed[p].next)
{
int to = ed[p].y;
if(dis[to] > dis[now.id] + 1)
{
dis[to] = dis[now.id] + 1;
pq.push(point(to, dis[to]));
}
}
}
}
struct node
{
int d1, dn;
node(){}
node(int a, int b)
{
d1 = a;
dn = b;
}
bool operator<(const node &x) const
{
return d1-dn < x.d1-x.dn;
}
}nd[200010];
int dis1[200010];
int disn[200010];
int maxy[400010];
int ans;
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= k; i++)
{
cin >> a[i];
}
for(int i = 1; i <= m; i++)
{
int x, y;
cin >> x >> y;
add_edge(x, y);
add_edge(y, x);
}
Dijkstra(1);
for(int i = 1; i <= n; i++)
{
dis1[i] = dis[i];
}
Dijkstra(n);
for(int i = 1; i <= n; i++)
{
disn[i] = dis[i];
}
for(int i = 1; i <= k; i++)
{
nd[i] = node(dis1[a[i]], disn[a[i]]);
}
sort(nd+1, nd+k+1);
for(int i = k; i >= 1; i--)
{
maxy[i] = max(maxy[i+1], nd[i].dn);
}
for(int i = 1; i < k; i++)
{
ans = max(ans, nd[i].d1 + maxy[i+1] + 1);
}
ans = min(ans, dis1[n]);
cout << ans << endl;
return 0;
}
小結:
上次洛谷二月月賽T4我又有新思路了, 去看一看吧。