CCPC网络赛三场

9月15日更新CCPC三场比赛题解

写在前面的话

虽然cf没到组队线但却因为女队缘故侥幸组队。
来到楼下直接被知识海洋淹没。
但是大部分时候都没得选择,压力是自己给的,谁愿意堕落的话都可以活得很轻松的。
9月20号如果能打到女队前60名才有省赛比赛资格,我不会错过任何机会的。
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!!!!!!!!!!!!

Nikr:
你身上所有让我喜欢的特质,只要还有吸引力并且适合,我全部都会学过来,而且目标是比你做得更好。

Round 1

A - Vertex Cover HDU - 6150
As we know, minimumvertexcover is a classical NP-complete problem. There will not be polynomial time algorithm for it unless P=NP.

You can see the definition of vertex cover in https://en.wikipedia.org/wiki/Vertex_cover.

Today, little M designs an “approximate” algorithm for vertex cover. It is a greedy algorithm. The main idea of her algorithm is that always choosing the maximum degree vertex into the solution set. The pseudo code of her algorithm is as follows:

We assume that the labels of the vertices are from 1 to n.

for (int i = 1; i <= n; ++i) {
use[i] = false;
deg[i] = degree of the vertex i;
}
int ans = 0;
while (true) {
int mx = -1, u;
for (int i = 1; i <= n; ++i) {
if (use[i])
continue;
if (deg[i] >= mx) {
mx = deg[i];
u = i;
}
}
if (mx <= 0)
break;
++ans;
use[u] = true;
for (each vertex v adjacent to u)
–deg[v];
}
return ans;

As a theory computer scientist, you immediately find that it is a bad algorithm. To show her that this algorithm dose not have a constant approximate factor, you need to construct an instance of vertex cover such that the solution get by this algorithm is much worse than the optimal solution.

Formally, your program need to output a simple undirected graph of at most 500 vertices. Moreover, you need to output a vertex cover solution of your graph. Your program will get Accept if and only if the solution size get by the above algorithm is at least three times as much as yours.

Input
There is no input.

Output
First, output two integer n and m in a line, separated by a space, means the number of the vertices and the number of the edges in your graph.
In the next m lines, you should output two integers u and v for each line, separated by a space, which denotes an edge of your graph. It must be satisfied that 1≤u,v≤n and your graph is a simple undirected graph.
In the next line, output an integer k(1≤k≤n), means the size of your vertex cover solution.
Then output k lines, each line contains an integer u(1≤u≤n) which denotes the label of a vertex in your solution. It must be satisfied that your solution is a vertex cover of your graph.

Sample Output
4 4
1 2
2 3
3 4
4 1
2
1
3

Hint
The sample output is just to exemplify the output format.

题意:
首先题目给你一个求最小顶点覆盖的近似算法:每次取度数最大的点删去它和其关联的所有边,继续该过程直到完成覆盖。现在要求你要构造一个足够“坏”的图,使得按照题目该出的近似算法求出的顶点覆盖集的规模>=你能给出的顶点覆盖规模,使得误差超过三倍。
输出构造的图和给出你的顶点覆盖。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <unordered_map>
#include <iomanip>

#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1000010
typedef long long ll;
using namespace std;
const int max_n = 3001;
bool vis[max_n][max_n];

using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n=100;
    int tot=0,m=0,w=1;
    for(int i=n+1;i<=4*n;i++)
    {
        m+=w;
        tot+=w;
        if(tot+w>n)
        {
            w++;
            tot=0;
        }
    }//计算边;
    cout<<4*n<<" "<<m<<endl;
    w=1;
    tot=0;
    for(int i=n+1;i<=4*n;i++)
    {
        for(int j=tot+1;j<=tot+w;j++)
        {
            cout<<j<<" "<<i<<endl;
            m++;
        }
        tot+=w;
        if(tot+w>n)
        {
            w++;
            tot=0;
        }
    }
    cout<<n<<endl;
    for(int i=1;i<=n;i++) cout<<i<<endl;
    return 0;
}

尝试分析

首先可以把它当成一个二分图,左边点数为n(贪心结果),右边点数为3n(正确答案)。
设左边n个点,标号是1到n。对于每个 i∈[1,n],都在右边新建 ⌊ni⌋个点,每个点都选择左边的i个点连1条边,使得左边每个点最多只被多加了一条边。这样构造完成后可以发现贪心的做法会把右边那 nlogn个点当做一个覆盖集,实际上只需左边的n个点即可。
这位图画的很清楚


C - Friend-Graph HDU - 6152

It is well known that small groups are not conducive of the development of a team. Therefore, there shouldn’t be any small groups in a good team.
In a team with n members,if there are three or more members are not friends with each other or there are three or more members who are friends with each other. The team meeting the above conditions can be called a bad team.Otherwise,the team is a good team.
A company is going to make an assessment of each team in this company. We have known the team with n members and all the friend relationship among these n individuals. Please judge whether it is a good team.

Input
The first line of the input gives the number of test cases T; T test cases follow.(T<=15)
The first line od each case should contain one integers n, representing the number of people of the team.(n≤3000).
Then there are n-1 rows. The ith row should contain n-i numbers, in which number aij represents the relationship between member i and member j+i. 0 means these two individuals are not friends. 1 means these two individuals are friends.

Output
Please output ”Great Team!” if this team is a good team, otherwise please output “Bad Team!”.

Sample Input
1
4
1 1 0
0 0
1

Sample Output
Great Team!

题意分析
若有三个人彼此不认识或者认识,就不符合。
等于说画成图不能有三角形,也不能出现三个人完全无关。
发现如果小于等于两个人,一定是好团队,怎么可能有三人小团体呢。
发现如果大于等于六个人,一定不是好团队。
因为画不出来。
拉姆齐(Ramsey)定理
在组合数学上,拉姆齐(Ramsey)定理是要解决以下的问题:要找这样一个最小的数n,使得n个人中必定有k个人相识或l个人互不相识。 拉姆齐定理的通俗表述: 6 个人中至少存在3人相互认识或者相互不认识。 该定理等价于证明这6个顶点的完全图的边,用红、蓝二色任意着色,必然至少存在一个红色边三角形,或蓝色边三角形。
现在要考虑的只要n=3/4/5三种情况。

int flag = 0;
for (int i = 0; i <= n-1; i++)
for (int j = i + 1; j <= n-1; j++)
for (int m = j + 1; m <= n-1; m++) {
int sum = vis[i][j] + vis[j][m] + vis[i][m];
if (sum == 0 || sum == 3)
flag = 1;
}
if (flag) printf(“Bad Team!\n”);
else printf(“Great Team!\n”);

也就是说,i,j,m的关系不能同时是朋友(sum3),或者同时不是朋友(sum0)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <unordered_map>
#include <iomanip>

#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1000010
typedef long long ll;
using namespace std;
const int max_n = 3001;
bool vis[max_n][max_n];

int main() {
    int T, n, temp;
    scanf("%d",&T);
    while (T--) {
        memset(vis, 0, sizeof(vis));
        scanf("%d",&n);
        for (int i = 0; i < n-1; i++)
            for (int j = i + 1; j <= n-1; j++) {
                scanf("%d",&temp);
                vis[i][j] = vis[j][i] = temp;
            }
        if (n <= 2)
            printf("Great Team!\n");
        else if (n >=6)
            printf("Bad Team!\n");


        else {
            int flag = 0;
            for (int i = 0; i <= n-1; i++)
                for (int j = i + 1; j <= n-1; j++)
                    for (int m = j + 1; m <= n-1; m++) {
                        int sum = vis[i][j] + vis[j][m] + vis[i][m];
                        if (sum == 0 || sum == 3)
                            flag = 1;
                    }
            if (flag)  printf("Bad Team!\n");
            else  printf("Great Team!\n");
        }
    }

}

D - A Secret HDU - 6153

Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,which have a big secret.SF is interested in this secret and ask VS how to get it.There are the things that VS tell:
Suffix(S2,i) = S2[i…len].Ni is the times that Suffix(S2,i) occurs in S1 and Li is the length of Suffix(S2,i).Then the secret is the sum of the product of Ni and Li.
Now SF wants you to help him find the secret.The answer may be very large, so the answer should mod 1000000007.

Input
Input contains multiple cases.
The first line contains an integer T,the number of cases.Then following T cases.
Each test case contains two lines.The first line contains a string S1.The second line contains a string S2.
1<=T<=10.1<=|S1|,|S2|<=1e6.S1 and S2 only consist of lowercase ,uppercase letter.

Output
For each test case,output a single line containing a integer,the answer of test case.
The answer may be very large, so the answer should mod 1e9+7.

Sample Input
2
aaaaa
aa
abababab
aba

Sample Output
13
19

Hint
case 2:
Suffix(S2,1) = “aba”,
Suffix(S2,2) = “ba”,
Suffix(S2,3) = “a”.
N1 = 3,
N2 = 3,
N3 = 4.
L1 = 3,
L2 = 2,
L3 = 1.
ans = (33+32+4*1)%1000000007.

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#define INF 0x3f3f3f3f

#define N 1000005
typedef unsigned long long ll;
using namespace std;

const int MOD = 1e9+7;
const int maxn=1e6 + 10;   //字符串长度最大值
int nxt[maxn],ex[maxn]; //ex数组即为extend数组
//预处理计算next数组
inline void GETNEXT(char *str)
{
    int i=0,j,po,len=strlen(str);
    nxt[0]=len;//初始化next[0]
    while(str[i]==str[i+1]&&i+1<len)//计算next[1]
        i++;
    nxt[1]=i;
    po=1;//初始化po的位置
    for(i=2; i<len; i++)
    {
        if(nxt[i-po]+i<nxt[po]+po)//第一种情况,可以直接得到next[i]的值
            nxt[i]=nxt[i-po];
        else//第二种情况,要继续匹配才能得到next[i]的值
        {
            j=nxt[po]+po-i;
            if(j<0)
                j=0;//如果i>po+nxt[po],则要从头开始匹配
            while(i+j<len&&str[j]==str[j+i])//计算next[i]
                j++;
            nxt[i]=j;
            po=i;//更新po的位置
        }
    }
}
//计算extend数组
inline void EXKMP(char *s1,char *s2)
{
    int i=0,j,po,len=strlen(s1),l2=strlen(s2);
    GETNEXT(s2);//计算子串的next数组
    while(s1[i]==s2[i]&&i<l2&&i<len)//计算ex[0]
        i++;
    ex[0]=i;
    po=0;//初始化po的位置
    for(i=1; i<len; i++)
    {
        if(nxt[i-po]+i<ex[po]+po)//第一种情况,直接可以得到ex[i]的值
            ex[i]=nxt[i-po];
        else//第二种情况,要继续匹配才能得到ex[i]的值
        {
            j=ex[po]+po-i;
            if(j<0)
                j=0;//如果i>ex[po]+po则要从头开始匹配
            while(i+j<len&&j<l2&&s1[j+i]==s2[j])//计算ex[i]
                j++;
            ex[i]=j;
            po=i;//更新po的位置
        }
    }
}

inline ll sum(ll n)
{
    return ((n % MOD) * ((n + 1) % MOD) / 2) % MOD;
}

char s1[N], s2[N];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("\n%s", s1);
        scanf("\n%s", s2);
        int len1 = strlen(s1);
        int len2 = strlen(s2);
        reverse(s1, s1 + len1);
        reverse(s2, s2 + len2);
        memset(nxt, 0, sizeof(nxt));
        memset(ex, 0, sizeof(ex));
        EXKMP(s1, s2);
        ll ans = 0;
        for(int i = 0; i < len1; i++)
        {
            if(ex[i])
            {
                ans = (ans + sum(ex[i]) % MOD) % MOD;
            }
        }
        printf("%lld\n", ans % MOD);
    }
    return 0;
}

题意分析
KMP算法了。

KMP算法详细解释,这个博主太厉害了!

图源链接

if(P1…Pj-1 == P2…Pj) => next[j+1]=j
else if(P1…Pj-2 == P3…Pj) =>next[j+1]=j-1
else if(P1…Pj-3 == P4…Pj) =>next[j+1]=j-2



else if(P1P2 == Pj-1Pj) => next[j+1]=3
else if(P1 == Pj-1) => next[j+1]=2
else if(P1 != Pj-1) => next[j+1]=1
每次前去尾1个,后掐头1个,直至得到next[j+1]

int GetNext(char ch[],int cLen,int next[]){//cLen为串ch的长度
    next[1] = 0;
    int i = 1,j = 0;
    while(i<=cLen){
        if(j==0||ch[i]==ch[j]) next[++i] = ++j;
        else j = next[j];
    }
}


E - CaoHaha’s staff HDU - 6154

“You shall not pass!”
After shouted out that,the Force Staff appered in CaoHaha’s hand.
As we all know,the Force Staff is a staff with infinity power.If you can use it skillful,it may help you to do whatever you want.
But now,his new owner,CaoHaha,is a sorcerers apprentice.He can only use that staff to send things to other place.
Today,Dreamwyy come to CaoHaha.Requesting him send a toy to his new girl friend.It was so far that Dreamwyy can only resort to CaoHaha.
The first step to send something is draw a Magic array on a Magic place.The magic place looks like a coordinate system,and each time you can draw a segments either on cell sides or on cell diagonals.In additional,you need 1 minutes to draw a segments.
If you want to send something ,you need to draw a Magic array which is not smaller than the that.You can make it any deformation,so what really matters is the size of the object.
CaoHaha want to help dreamwyy but his time is valuable(to learn to be just like you),so he want to draw least segments.However,because of his bad math,he needs your help.

Input
The first line contains one integer T(T<=300).The number of toys.
Then T lines each contains one intetger S.The size of the toy(N<=1e9).

Output
Out put T integer in each line ,the least time CaoHaha can send the toy.

Sample Input
5
1
2
3
4
5

Sample Output
4
4
6
6
7

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <unordered_map>
#include <iomanip>

#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1000010
typedef long long ll;
using namespace std;
const int max_n = 3001;
bool vis[max_n][max_n];

int main() {
    int T;
    int n;
    double sum = 2;
    int temp;
    scanf("%d", &T);
    while (T--) {
        temp = 4;
        scanf("%d", &n);
        while (n) {
            if (sum >= n)
                break;
            temp++;
            if (temp % 4 == 1)
                sum += 0.5 + temp / 4 - 1;
            else if (temp % 4 == 2)sum += 1.5 + temp / 4 - 1;
            else if (temp % 4 == 3)sum += 1.5 + temp / 4 - 1;
            else sum += 2.5 + temp / 4 - 1 - 1;

        }
        sum=2;
        printf("%d\n", temp);
    }

}

老找规律画图求解的思维题了。
这个图画的很灵清!

Round 2

A - ^&^HDU - 6702

Bit operation is a common computing method in computer science ,Now we have two positive integers A and B ,Please find a positive integer C that minimize the value of the formula (A xor C) & (B xor C) .Sometimes we can find a lot of C to do this ,So you need to find the smallest C that meets the criteria .

For example ,Let’s say A is equal to 5 and B is equal to 3 ,we can choose C=1,3… ,so the answer we’re looking for C is equal to 1.

If the value of the expression is 0 when C=0, please print 1.

Input
The input file contains T test samples.(1<=T<=100)
The first line of input file is an integer T.
Then the T lines contains 2 positive integers, A and B, (1≤A,B<232)

Output
For each test case,you should output the answer and a line for each answer.

Sample Input
1
3 5

Sample Output
1

题意分析
其实就是找出最小的值c使(a^c)&(b^c)最小。
根据分配律,原式=(A&B) xor C;
A,B已知,则(A&B)为固定值,又根据xor(异或)知识:同为0,异为1,则要想使原式最小,C要==(A&B)才行,因为两个数异或运算,如果两个数相同,同为0,结果最小。
所以C=(A&B)。
又根据题意最后一句:If the value of the expression is 0 when C=0, please print 1.

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
typedef long long ll;

using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    ll a, b;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>a>>b;
        if((a&b)==0)
            cout<<1<<endl;
        else
            cout<<(a&b)<<endl;
    }
    return 0;
}

F - Shuffle Card HDU - 6707

A deck of card consists of n cards. Each card is different, numbered from 1 to n. At first, the cards were ordered from 1 to n. We complete the shuffle process in the following way, In each operation, we will draw a card and put it in the position of the first card, and repeat this operation for m times.

Please output the order of cards after m operations.

Input
The first line of input contains two positive integers n and m.(1<=n,m<=105)
The second line of the input file has n Numbers, a sequence of 1 through n.
Next there are m rows, each of which has a positive integer si, representing the card number extracted by the i-th operation.

Output
Please output the order of cards after m operations. (There should be one space after each number.)

Sample Input
5 3
1 2 3 4 5
3
4
3

Sample Output
3 4 1 2 5

题意分析
最开始给出一个排列,然后m次操作,把a移动到最前面,
模拟栈。每次把给出的数放到栈顶,输出的时候记录一下如果已经输出过就不用再输出。比较坑的就是末尾不能输出换行,否则PE。

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
#define ll long long
using namespace std;
const int MAX = 1e5 + 10;
const ll INF = 1e9 + 7;
stack<int>ans;
int a[MAX];
bool vis[MAX];
int main() {
    int m, n;
    while(scanf("%d%d", &n, &m)!= EOF) {
        for(int i = 0; i < n; i++) scanf("%d", &a[i]);
        for(int i = n - 1; i >= 0; i--) {
            ans.push(a[i]);
        }
        for(int i = 0; i < m; i++) {
            int x;
            scanf("%d", &x);
            ans.push(x);
        }
        memset(vis, 0, sizeof(vis));
        while(ans.size()) {
            int top = ans.top();
            ans.pop();
            if(vis[top] == 0) {
                vis[top] = 1;
                printf("%d ", top);
            }
        }

    }
}

G - Windows Of CCPC HDU - 6708
In recent years, CCPC has developed rapidly and gained a large number of competitors .One contestant designed a design called CCPC Windows .The 1-st order CCPC window is shown in the figure:
CC
PC
And the 2-nd order CCPC window is shown in the figure:
We can easily find that the window of CCPC of order k is generated by taking the window of CCPC of order k−1 as C of order k, and the result of inverting C/P in the window of CCPC of order k−1 as P of order k.
And now I have an order k ,please output k-order CCPC Windows , The CCPC window of order k is a 2k∗2k matrix.

Input
The input file contains T test samples.(1<=T<=10)
The first line of input file is an integer T.
Then the T lines contains a positive integers k , (1≤k≤10)

Output
For each test case,you should output the answer .

Sample Input
3
1
2
3

Sample Output
CC
PC
CCCC
PCPC
PPCC
CPPC
CCCCCCCC
PCPCPCPC
PPCCPPCC
CPPCCPPC
PPPPCCCC
CPCPPCPC
CCPPPPCC
PCCPCPPC

题意分析
最开始是4个字符,左下角那个和其余3个不一样,
用最初的可以拼成第2个,把第2个分成4部分,左下角和第一个相反,也就是P变为C,C变为P,其余相同。
一共要输出2^n行,那么可以一行一行的输出。
假设我要输出总行为8行,现在要输出第1行,
那么其实是输出总行为4行时的第1行输出两遍,
输出左下角的部分时,这是总行为4行的相应行相反输出1遍,再输出1遍相同的。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#define INF 0x3f3f3f3f
#define pi acos(-1)
#define N 1000005
using namespace std;

typedef unsigned long long ll;

bool mt[1024][1024];

void init()
{
    mt[0][0] = mt[0][1] = mt[1][1] = 1;
    mt[1][0] = 0;
    for(int k = 2; k <= 10; k++)
    {
        int l= pow(2, k - 1);
        for(int i = 0; i < l; i++)
        {
            for(int j = 0; j < l; j++)
            {
                mt[i][j + l] = mt[i + l][j + l] = mt[i][j];
                if(mt[i][j])
                    mt[i + l][j] = 0;
                else
                    mt[i + l][j] = 1;
            }
        }
    }
}

int main()
{
    init();
    int T;
    cin >> T;
    while(T--)
    {
        int k;
        cin >> k;
        for(int i = 0; i < pow(2, k); i++)
        {
            for(int j = 0; j < pow(2, k); j++)
            {
                if(mt[i][j])
                    cout << 'C';
                else
                    cout << 'P';
            }
            cout << endl;
        }
    }
    return 0;
}

H - Fishing Master HDU - 6709

Heard that eom is a fishing MASTER, you want to acknowledge him as your mentor. As everybody knows, if you want to be a MASTER’s apprentice, you should pass the trial. So when you find fishing MASTER eom, the trial is as follow:

There are n fish in the pool. For the i - th fish, it takes at least ti minutes to stew(overcook is acceptable). To simplify this problem, the time spent catching a fish is k minutes. You can catch fish one at a time and because there is only one pot, only one fish can be stewed in the pot at a time. While you are catching a fish, you can not put a raw fish you have caught into the pot, that means if you begin to catch a fish, you can’t stop until after k minutes; when you are not catching fish, you can take a cooked fish (stewed for no less than ti) out of the pot or put a raw fish into the pot, these two operations take no time. Note that if the fish stewed in the pot is not stewed for enough time, you cannot take it out, but you can go to catch another fish or just wait for a while doing nothing until it is sufficiently stewed.

Now eom wants you to catch and stew all the fish as soon as possible (you definitely know that a fish can be eaten only after sufficiently stewed), so that he can have a satisfying meal. If you can complete that in the shortest possible time, eom will accept you as his apprentice and say “I am done! I am full!”. If you can’t, eom will not accept you and say “You are done! You are fool!”.

So what’s the shortest time to pass the trial if you arrange the time optimally?

Input
The first line of input consists of a single integer T(1≤T≤20), denoting the number of test cases.
For each test case, the first line contains two integers n(1≤n≤105),k(1≤k≤109), denoting the number of fish in the pool and the time needed to catch a fish.
the second line contains n integers, t1,t2,…,tn(1≤ti≤109) ,denoting the least time needed to cook the i - th fish.

Output
For each test case, print a single integer in one line, denoting the shortest time to pass the trial.

Sample Input
2
3 5
5 5 8
2 4
3 3

Sample Output
23
11

Hint
Case 1: Catch the 3rd fish (5 mins), put the 3rd fish in, catch the 1st fish (5 mins), wait (3 mins),
take the 3rd fish out, put the 1st fish in, catch the 2nd fish(5 mins),
take the 1st fish out, put the 2nd fish in, wait (5 mins), take the 2nd fish out.
Case 2: Catch the 1st fish (4 mins), put the 1st fish in, catch the 2nd fish (4 mins),
take the 1st fish out, put the 2nd fish in, wait (3 mins), take the 2nd fish out.

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>

typedef long long ll;
#define INF 0x3f3f3f3f
#define pi acos(-1)
const int max_n = 1e5 + 11;

using namespace std;

bool cmp(int a, int b) {
    return a > b;
}

int main() {

    ll t;
   scanf("%lld",&t);
    while (t--) {
        int a[max_n]={0};
        int b[max_n]={0};
       // memset(a, 0, sizeof(a));
      //  memset(b, 0, sizeof(b));
        ll n, k;
        scanf("%lld%lld",&n,&k);
        ll ans = 0;
        ll num = 1;
        for (int i = 0; i < n; i++) {
            scanf("%d",&a[i]);
            ans += a[i];
            num += a[i] / k;
            b[i] = a[i] % k;
        }
        ans += k;
        if (num >= n) {
            printf("%lld\n",ans);
        } else {
            sort(b, b + n, cmp);
            for (int i = 0; i < n - num; i++) {
                ans += k - b[i];
            }
            printf("%lld\n",ans);
        }
    }
}

题意分析
贪心算法
最理想的情况下, 需要花费的时间res = m + 烹饪所有鱼的时间总和。
但是有的情况下, 我们并不能在烹饪每条鱼时都恰好能去钓鱼, 所以我们需要将有些鱼多烹饪一些时间, 去额外钓一些鱼。
主要是尽可能的减少额外花费的时间.
当我们烹饪第i条鱼时, 我们可以不花费任何额外的时间钓鱼的数目为a[i] / m, 剩余的时间则为a[i] % m, 我们可以统计是否我们可以不花费任何额外时间钓完所有鱼, 如果不可以, 则我们需要在剩余时间最多的鱼烹饪后多花去m - a[i] % m的时间。

Round 3

A - A water problem HDU - 5832

Two planets named Haha and Xixi in the universe and they were created with the universe beginning.
There is 73 days in Xixi a year and 137 days in Haha a year.
Now you know the days N after Big Bang, you need to answer whether it is the first day in a year about the two planets.

Input
There are several test cases(about 5 huge test cases).
For each test, we have a line with an only integer N(0≤N), the length of N is up to 10000000.

Output
For the i-th test case, output Case #i: , then output “YES” or “NO” for the answer.

Sample Input
10001
0
333

Sample Output
Case #1: YES
Case #2: YES
Case #3: NO


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>

#define INF 0x3f3f3f3f
#define pi acos(-1)
const int max_n = 1e7 + 10;
using namespace std;

typedef unsigned long long ll;


int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    char str[max_n];
    int cnt=0;
    while(scanf("%s",str)!=EOF){
        int ans = 0;int len=strlen(str);
        for(int i=0;i<len;i++){
            ans=(ans*10+str[i]-'0')%10001;
        }
        if(ans==0)printf("Case #%d: YES\n",++cnt);
        else printf("Case #%d: NO\n",++cnt);
    }

}

题意分析
个么其实就是大数问题。
因为73和137互质,直接使用他们的乘积即可。
一般的取模方法会超时,因为输入的大整数的长度为10000000,这里必须用特殊的分段取模方法。

大数取余模版

while(scanf("%s", num) != EOF)//输入大数
{
int len = strlen(num);
long long ans = 0;
for(int i = 0; i < len; ++i)
{
ans = ans*10 + (num[i]-‘0’);
ans %= MODZ;
}
}


D - Danganronpa HDU - 5835

Chisa Yukizome works as a teacher in the school. She prepares many gifts, which consist of n kinds with a[i] quantities of each kind, for her students and wants to hold a class meeting. Because of the busy work, she gives her gifts to the monitor, Chiaki Nanami. Due to the strange design of the school, the students’ desks are in a row. Chiaki Nanami wants to arrange gifts like this:

  1. Each table will be prepared for a mysterious gift and an ordinary gift.

  2. In order to reflect the Chisa Yukizome’s generosity, the kinds of the ordinary gift on the adjacent table must be different.

  3. There are no limits for the mysterious gift.

  4. The gift must be placed continuously.

She wants to know how many students can get gifts in accordance with her idea at most (Suppose the number of students are infinite). As the most important people of her, you are easy to solve it, aren’t you?

Input
The first line of input contains an integer T(T≤10) indicating the number of test cases.
Each case contains one integer n. The next line contains n (1≤n≤10) numbers: a1,a2,…,an, (1≤ai≤100000).

Output
For each test case, output one line containing “Case #x: y” (without quotes) , where x is the test case number (starting from 1) and y is the answer of Chiaki Nanami’s question.

Sample Input
1
2
3 2

Sample Output
Case #1: 2


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>

#define INF 0x3f3f3f3f
#define pi acos(-1)
using namespace std;

typedef unsigned long long ll;

int main()
{
    int T;
    scanf("%d",&T);
    for(int i = 1; i<=T ; i++)
    {
        int n;
        scanf("%d",&n);
        int sum1 = 0,Max = 0;
        for(int j=1;j<=n;j++)
        {
            int temp;
            scanf("%d",&temp);
            if(temp>Max)
            Max=temp;
            sum1 += temp;
        }
        printf("Case #%d: %d\n",i,min(sum1/2,2*(sum1-Max)+1));
    }
    return 0;
}

题意分析

  1. 我们考虑有无数量“绝对大”的礼物,绝对大即该种礼物的总数比其他种类的所有礼物的总数还要多。那么,能否发给多少人就与这个绝对大的礼物有关。
    先分配普通礼物:我们把其他礼物按间隔为1摆放,然后让绝对大的礼物去插空。然后多余的去填补神秘礼物.
    如果神秘礼物也能填补完。
    sum=其他礼物数*2+1
    如果填补不完,就从普通礼物后面截取然后往神秘礼物填,直到神秘和普通数量相同.
    sum=(其他礼物+总数最大的礼物个数)/2
  2. 没有“绝对大”礼物。
    sum=总礼物数/2

K - Lweb and String HDU - 5842

Lweb has a string S.
Oneday, he decided to transform this string to a new sequence.
You need help him determine this transformation to get a sequence which has the longest LIS(Strictly Increasing).
You need transform every letter in this string to a new number.
A is the set of letters of S, B is the set of natural numbers.
Every injection f:A→B can be treat as an legal transformation.
For example, a String “aabc”, A={a,b,c}, and you can transform it to “1 1 2 3” and the LIS of the new sequence is 3.
Now help Lweb, find the longest LIS which you can obtain from S.
LIS: Longest Increasing Subsequence. (https://en.wikipedia.org/wiki/Longest_increasing_subsequence)

Input
The first line of the input contains the only integer T,(1≤T≤20).
Then T lines follow, the i-th line contains a string S only containing the lowercase letters, the length of S will not exceed 105.

Output
For each test case, output a single line “Case #x: y”, where x is the case number, starting from 1. And y is the answer.

Sample Input
2
aabcc
acdeaa

Sample Output
Case #1: 3
Case #2: 4

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
using namespace std;
const int MAX = 1e9 + 7;
int main() {
    int T;
    scanf("%d", &T);
    int cnt = 0;
    while(T--) {
        string a;
        set<char>ans;
        cin >> a;
        for(int i = 0; i < a.length(); i++) {
            ans.insert(a[i]);
        }
        cnt++;
        printf("Case #%d: %d\n", cnt, (int)ans.size());
    }
}

题意分析
给你一个均由小写字母组成的字符串,你可以重新定义每个字母的相对大小,问各种定义下严格的最长递增子序列的最大值。
由于可以自定义各个字母的最大值,因此实际上答案就是不同字母的个数。

关于LIS最长递增子序列

// 这里的最长递增子序列是允许中间跨越其他子序列的 
#include<iostream>
#include<algorithm>
using namespace std;

int *arr;
int *dp;

// 经典问题 dp[i]的意思为以i为结尾的最长子序列为多少 
int getResult(int n){
	dp[0] = 1;
	for(int i = 0; i < n; i++){
		int cnt = 1;
		for(int j = i-1; j >= 0; j--){
			if(arr[i] > arr[j]){  // 保证递增 
				cnt = max(cnt, dp[j]+1);
			}
		}
		dp[i] = cnt;
	}
	int ans = 0;
	for(int i = 0; i < n; i++){
		ans = max(ans, dp[i]);
	}
	return ans;
}

// 二分查找变体 找到第一个大于n的位置index 
int BinarySearch(int *dp, int len, int n){
	int left = 1;
	int right = len;
	while(left < right){
		int mid = (left+right)/2;
		if(dp[mid] > n){
			right = mid;
		}
		else{
			left = mid+1;
		}
	}
	return right;
}

// 优化的dp dp数组的最终下标为答案 
int getResult1(int n){
	 dp[1] = arr[0];
	 int index = 1;
	 for(int i = 1; i < n; i++){
	 	if(arr[i] > dp[index]){
	 		// 更新index 
	 		dp[++index] = arr[i];
		 }
		 else{
		 	// 把dp数组中第一个大于n的数字替换为arr[i] 
		 	int tempIndex = BinarySearch(dp, index, arr[i]);
		 	dp[tempIndex] = arr[i];
		 }
	 }
	 return index;
} 

int main(){
	int n;
	while(cin >> n){
		arr = new int[n];
		dp = new int[n+1];
		for(int i = 0; i < n; i++){
			cin >> arr[i];
		}
		int ans = getResult1(n);
		cout << ans << endl;
		delete[] arr;
		delete[] dp;
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值