题目链接:http://codeforces.com/contest/1178
A Prime Minister(贪心)
题意:Alice(下标为1)从n个数中选取数,每个数不能超过a[1]/2,选取数的总和超过sum/2,输出任意方案,无解输出0
题解:直接贪心取数即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=500010;//
int a[maxn];
vector<int> ve;
int n;
int main()
{
while(~scanf("%d",&n)){
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);sum+=a[i];
}
ve.clear();
ve.push_back(1);
int cur=a[1];
for(int i=2;i<=n;i++){
if(cur*2>sum) break;
if(a[i]*2<=a[1]){
cur+=a[i];ve.push_back(i);
}
}
if(cur*2<=sum){
printf("0\n");
}else{
int len=ve.size();
printf("%d\n",len);
for(int i=0;i<len;i++){
printf("%d%c",ve[i],i==len-1?'\n':' ');
}
}
}
return 0;
}
B WOW Factor(简单dp)
题意:给一个v0串,问wow子串数,其中这里的w由两个连续的v组成。
题解:记录所有的v子串,扫一遍o的位置,每次加上left*(all-left)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1000010;//
char s[maxn];
vector<int> ve,ve2;
int len[maxn];
int main()
{
while(~scanf("%s",s)){
int n=strlen(s);
ve.clear();
memset(len,0,sizeof(len));//
ll all=0;
for(int i=0;i<n;i++){
if(s[i]=='o') ve.push_back(i);
else{
int pos=i,cur=i;
while((i+1)<n&&s[i+1]=='v'){
pos=++i;
}
if(pos>cur){
ve2.push_back(cur),len[cur]=pos-cur+1;
all+=len[cur]-1;
}
}
}
ll left=0,ans=0;
vector<int>::iterator cur=ve2.begin();
for(auto i:ve){
while(cur<ve2.end()&&*cur<i){
left+=len[*cur]-1;cur++;
}
ans+=left*(all-left);
}
printf("%I64d\n",ans);
}
}
C Tiles
题意:给你wh的房间,需要wh个地板来填充,地板长这样,要求相邻地板邻接边颜色不同,问多少铺法
题解:固定第一块,有4种取法,再往右和往下填,都是2种,对于一个左边和右边都被填充的地板,其填充是固定的。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
const int maxn=1000010;//
int main()
{
int w,h;
while(~scanf("%d%d",&w,&h)){
ll ans=4;
for(int i=1;i<w;i++) ans=ans*2%mod;
for(int i=1;i<h;i++) ans=ans*2%mod;
printf("%I64d\n",ans);
}
return 0;
}
D Prime Graph
参考:https://www.cnblogs.com/qieqiemin/p/11223610.html
题意:给你n,要求构造一个图,使得图边数是素数,且每个结点的度也是素数
题解:如果n是素数,那么我们直接连一个环即可;否则的话,利用一个结论,[n,n+n/2]必然存在一个素数,我们连完环后,从1开始,向它的对边连边,再从2开始继续这个过程,我们最多连n/2次,一定能找到一个素数,且每个结点的度数要么为2要么为3。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
const int maxn=1010;//
bool isPrime[maxn+10];
int prime[maxn],pn;//
void getPrime()
{
memset(isPrime,1,sizeof(isPrime));
isPrime[0]=isPrime[1]=0;
pn=0;
for(long long i=2;i<maxn;i++)
{
if(isPrime[i])
prime[pn++]=i;
for(int j=0;j<pn&&prime[j]*i<maxn;j++)
{
isPrime[prime[j]*i]=0;
if(i%prime[j]==0) break;
}
}
}
int main()
{
getPrime();
int n;
while(~scanf("%d",&n)){
if(isPrime[n]){
printf("%d\n",n);
for(int i=1;i<n;i++){
printf("%d %d\n",i,i+1);
}
printf("%d %d\n",n,1);
}else{
int cur=n,ans=n;
while(!isPrime[ans]) ans++;
printf("%d\n",ans);
for(int i=1;i<n;i++){
printf("%d %d\n",i,i+1);
}
printf("%d %d\n",n,1);
int id=1;
while(!isPrime[cur]){
cur++;
printf("%d %d\n",id,id+n/2);
id++;
}
}
}
return 0;
}
E Archaeology
参考:https://blog.csdn.net/starlet_kiss/article/details/97813132
题意:给一个由a b c构成的字符串,相邻位置的字符不同,要求构造长度不小于|s|/2的回文子串
题解:由于只有3个字符,且相邻位置的字符不同,4个字符中必然有2个相同,我们左右取字符即可。一开始wa了,参考了别人题解,才知道4个字符这个关键点。(tcl)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
const int maxn=1000010;
bool vis[maxn];
char s[maxn];
int n;
int main()
{
while(~scanf("%s",s)){
memset(vis,0,sizeof(vis));
n=strlen(s);
if(n<=3){
putchar(s[0]);puts("");continue;
}
int l=0,r=n-1;
while(l<r){
if(s[l]==s[r]) vis[l]=vis[r]=1;
else if(s[l]==s[r-1]) vis[l]=vis[r-1]=1;
else if(s[l+1]==s[r]) vis[l+1]=vis[r]=1;
else vis[l+1]=vis[r-1]=1;
l+=2;r-=2;
}
for(int i=0;i<n;i++) if(vis[i]) putchar(s[i]);
puts("");
}
return 0;
}
F1. Short Colorful Strip(区间DP)
代码&参考:https://www.cnblogs.com/Dup4/p/11220155.html#f1.-short-colorful-strip
题意:给定n和m(n==m)有n种颜色,把1到n位置的布分别染成ai种颜色,保证对于每种颜色在ai中都出现。问按颜色从小到大染色,有多少种染色方法。
题解:区间dp,找到当前区间最小颜色位置,对两边情况直接分开dp,再相乘。
F2 Long Colorful Strip (区间DP,好题)
代码参考:CF why112
题意:给定n和m,有n种颜色,把1到n位置的布分别染成ai种颜色,问按颜色从小到大染色,有多少种染色方法。
题解:很棒的区间DP,对于相邻的相同颜色,去重;DP时左边 * 中间 * 右边。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=510;
const int maxm=1000010;
const int mod=998244353;
int n,m;
int a[maxm];
struct node{
int l,r,len;
int a[maxn*2];
void init(){
l=r=len=0;
}
void insert(int x){
a[len++]=x;
if(len==1)
l=r=x;
else r=x;
}
}s[maxn];
void Add(ll &x,ll y)
{
x+=y;
if(x>=mod) x-=mod;
}
ll dp[maxn*2][maxn*2];
ll dfs(int l,int r)
{
//printf("l:%d r:%d \n",l,r);
if(l>r) return 1;
if(dp[l][r]!=-1) return dp[l][r];
int pos=a[l];
for(int i=l+1;i<=r;i++) if(a[i]<pos) pos=a[i];
if(l==r){
if(s[pos].l<l||s[pos].r>r) return dp[l][r]=0;
else return dp[l][r]=1;
}
ll ans1=0,ans2=1,ans3=0;
if(l==s[pos].l) ans1=1;else
for(int i=l;i<=s[pos].l;i++){//注意i的取值,防止死循环、算漏,下同
Add(ans1,dfs(l,i-1)*dfs(i,s[pos].l-1)%mod);
}
if(r==s[pos].r) ans3=1;else
for(int i=s[pos].r;i<=r;i++){
Add(ans3,dfs(s[pos].r+1,i)*dfs(i+1,r)%mod);
}
if(s[pos].len==1) ans2=1;else
for(int i=0;i<s[pos].len-1;i++){
ans2=ans2*dfs(s[pos].a[i]+1,s[pos].a[i+1]-1)%mod;
}
return dp[l][r]=ans1*ans2%mod*ans3%mod;
}
int main()
{
while(~scanf("%d%d",&n,&m)){
int i=1,x;
for(int i=0;i<maxn;i++) s[i].init();
for(int i=1;i<=m;i++){
scanf("%d",&x);
if(i>1&&x==a[i-1]){
i--;m--;
}else{
a[i]=x;
s[x].insert(i);
}
}
if(m>=2*n){
printf("0\n");continue;
}
memset(dp,-1,sizeof(dp));
printf("%I64d\n",dfs(1,m));
}
return 0;
}
G The Awesomest Vertex(分块、斜率优化、dfn序)
实在不会,,留坑吧
上粉兔巨巨代码:https://www.cnblogs.com/PinkRabbit/p/CF1178G.html